Programmatic lookup/creation of (unmanaged) beans in CDI 1.1 - cdi

I'm currently upgrading our libraries to JavaEE 7 and I have some questions on how to lookup and create (unmanaged) bean instances. I've looked around some other questions here and on the internet and found quite different solutions. I've ignored qualifiers on my examples.
In the old implementation (for CDI 1.0) of the libraries I've only used Lookup #1 - even for #Dependent.
Lookup #1: The old way using BeanManager#getBeans()
public static <T> T getBean(Class<T> clazz) {
Bean<T> bean = (Bean<T>) _beanManager.resolve(_beanManager.getBeans(clazz));
if(bean.getScope().equals(Dependent.class)) {
throw new IllegalArgumentException("Cdi#getBean(Class) should only be invoked for classes that do not belong to the "
+ "#Dependent scope");
}
CreationalContext<T> ctx = _beanManager.createCreationalContext(bean);
return (T) _beanManager.getReference(bean, clazz, ctx);
}
I've added the if-statement because I've read at some other place, that #Dependent scoped beans shouldn't be created on this way (no well-defined lifecycle).
Lookup #2: The CDI-1.1-way
public static <T> T getBean(Class<T> clazz) {
return CDI.current().select(clazz).get();
}
Q1: Which one (#1 or #2) should be preferred in CDI 1.1 to perform programmatic lookup of managed beans? Any pros and cons? Other solutions available?
Dependent / Creation #1: Use Unmanged and UnmanangedInstance
public static <T> UnmanagedInstance<T> getDependentBean(Class<T> clazz) {
return new Unmanaged<>(clazz).newInstance();
}
The UnmanagedInstance could be wrapped in a class DependentProvider which calls produce(), inject(), postConstruct() in the constructor and preDestroy(), dispose() in the destroy method (to simplify the usage even more).
Dependent / Creation #2: Inspired by DeltaSpike
public static <T> DependentProvider<T> getDependentBean(Class<T> clazz) {
Bean<T> bean = (Bean<T>) _beanManager.resolve(_beanManager.getBeans(clazz));
CreationalContext<T> ctx = _beanManager.createCreationalContext(bean);
T instance = (T) _beanManager.getReference(bean, clazz, ctx);
return new DependentProvider<T>(bean, ctx, instance);
}
The returned provider has a destroy() method, to remove the created instance.
public void destroy() {
bean.destroy(instance, creationalContext);
}
What I'm missing in the implementation from DeltaSpike is the call to creationalContext.release(). Is this not required?
Creation #3: Instance => only possible in managed beans
#ViewScoped
class X implements Serializable {
#Inject Instance<MyObject> _myObjectProvider;
public void doSomething() {
MyObject obj = _myObjectProvider.get();
// ... work with obj
// call _myObjectProvider.destroy(obj) as soon as we're done with the instance of MyObject.
}
}
Q2: Again, which one (#1 or #2, #3) should be preferred for programmatic creation of unmanaged "beans"? Any pros and cons? Other solutions available?
Finally I have a question on how to check if a bean is already instantiated (e.g. a session scoped bean) or not. I came up with the following method (for non-#Dependant only):
public <T> boolean existsBeanInstance(String name) {
Bean<T> bean = (Bean<T>) _beanManager.resolve(_beanManager.getBeans(name));
Context beanScopeContext = _beanManager.getContext(bean.getScope());
return beanScopeContext.get(bean) != null;
}
Q3: Is this reliable?

Related

Inject different implementations based on application property in Quarkus

I have a Repository interface that has two implementations. One reads data from a locally stored CSV file while the other reads from an Amazon Dynamo DB. I would like to be able to switch between which implementation I'm using based on an application property or custom build profile. I would normally use a Factory to retrieve the correct class at runtime, but I would like to do this with injection if possible.
I found a similar question using Spring boot but couldn't find an equivalent that would work in Quarkus Spring choose bean implementation at runtime
I also tried implementing a Configuration class similar to what is found in the docs here but again didn't have much luck. https://quarkus.io/guides/cdi-reference#default_beans
It feels like I'm missing something obvious so any pointers would be much appreciated.
Here is a simple example of my classes:
#ApplicationScoped
public class ExampleService {
#Inject
ExampleRepository repository;
public List<Data> retrieveData() {
return repository.retrieveData();
}
}
public interface ExampleRepository {
List<Data> retrieveData();
}
#ApplicationScoped
public class DynamoRepository implements ExampleRepository {
#Override
public List<Data> retrieveData() {
//Get Data from DynamoDb
}
}
#ApplicationScoped
public class CsvRepository implements ExampleRepository {
#Inject
CsvBeanHandler csvBeanHandler;
#Inject
LocalFileReader fileReader;
#Override
public List<Data> retrieveData() {
// Get data from CSV
}
}
I currently also have the following in my application.yml:
com:
example:
application:
storage-type: 'CSV' # OR AMAZON_DYNAMO_DB
It looks like they've added this directly to the documentation:
https://quarkus.io/guides/cdi-reference#declaratively-choose-beans-that-can-be-obtained-by-programmatic-lookup
I feel a bit guilty pasting this much, but it's the SO way.
I can add that it is NOT like a Guice 'binding'; BOTH classes will be instantiated, but only one will be injected. Also unlike Guice, you cannot inject the interface (or I did it wrong) - you have to do what's shown below, with Instance.
Personally I just use constructor injection and then drop the value of the Instance wrapper into a final field, so I'm not crying about the extra step. I do miss the power and explicit bindings possible with Modules ala Guice, but the simplicity here has its own value.
5.16. Declaratively Choose Beans That Can Be Obtained by Programmatic Lookup
It is sometimes useful to narrow down the set of beans that can be
obtained by programmatic lookup via javax.enterprise.inject.Instance.
Typically, a user needs to choose the appropriate implementation of an
interface based on a runtime configuration property.
Imagine that we have two beans implementing the interface
org.acme.Service. You can’t inject the org.acme.Service directly
unless your implementations declare a CDI qualifier. However, you can
inject the Instance instead, then iterate over all
implementations and choose the correct one manually. Alternatively,
you can use the #LookupIfProperty and #LookupUnlessProperty
annotations. #LookupIfProperty indicates that a bean should only be
obtained if a runtime configuration property matches the provided
value. #LookupUnlessProperty, on the other hand, indicates that a bean
should only be obtained if a runtime configuration property does not
match the provided value.
#LookupIfProperty Example
interface Service {
String name();
}
#LookupIfProperty(name = "service.foo.enabled", stringValue = "true")
#ApplicationScoped
class ServiceFoo implements Service {
public String name() {
return "foo";
}
}
#ApplicationScoped
class ServiceBar implements Service {
public String name() {
return "bar";
}
}
#ApplicationScoped
class Client {
#Inject
Instance<Service> service;
void printServiceName() {
// This will print "bar" if the property "service.foo.enabled" is NOT set to "true"
// If "service.foo.enabled" is set to "true" then service.get() would result in an AmbiguousResolutionException
System.out.println(service.get().name());
}
}
If your request is to bind at startup time the right implementation based on a configuration property, I suppose your problem may be resolved used #Produces annotation:
public class ExampleRepositoryFactory {
#Config("storage-type")
String storageType;
#Produces
public ExampleRepository dynamoInstance() {
return storageType == "CSV" ? new CsvRepository() : new DynamoRepository();
}
}

JSF with custom Annotation

I am using primefaces version 5 and I am adding messages regarding to a specific actions like save :
public void save(Tenant tenant) {
tenantDao.save(tenant);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Save success"));
}
Since I had a lot of these actions I tried to simplify this by creating a custom annotation called Message:
#Target(Runtime)
#Retention(Method)
public #interface Message {
String value();
}
and in my dao class :
public class TenantDao {
#Message("Saved Successfully")
public Tenant save(Tenant t) {
return em.save(t);
}
}
To read this annotation I have overridden the ELResolver the method invoke
public Object invoke(ELContext context,
Object base,
Object method,
Class<?>[] paramTypes,
Object[] params) {
Object result = super.invoke(context,method,paramTypes,params);
Method m = base.getClass().getMethod(method,paramTypes);
if(m.getAnnotation(Message.class) != null) {
addMessahe(m.getAnnotation(Message.class).value());
}
return result;
}
This was called in property (rendered, update, ..) but not in action listener
After a lot of debugging I discovered that theactionListener is called from MethodExpression class. So, I wrapped the MethodExpression class, and override the method invoke.
The problem now is that there are no way to retreive the class Method from MethodExpression class, also if I used the expression #{tenantDao.save(tenant)} the method getMethodInfo from MethodExpression will throw an exception.
Are there any way to read tAnnotation from any jsf context ?
I know that using Spring with AOP may solve this but I am not using Spring now.
Thanks

spring: share value between annotated beans like jsf applicationscope

I am working on a project with jsf 2.2 on the web side and spring 4 on the business side. I have a web filter which receives a parameter from the request url. From this parameter I have to connect to a database. There are cases where there are different databases possible, so depending on the parameter I have to initiate a different database connection. The web filter looks like this:
#Component
public final class SecurityFilter implements Filter
{
#Autowired
private CommonEao commonEao;
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest)request;
String instance = req.getParameter("instance");
//I would like to have something here like:
// springContext.addParameter("instance", instance);
String company = req.getParameter("company");
commonEao.getConfiguration(company);
... Do stuff
}
}
How does it works? The commonEao contains methods to make queries to the database (JPA/Eclipselink...). At initialization, no entityManager is present in commonEao since it is injected in SecurityFilter before the doFilter is executed when an url is requested. After the url is requested, the instance of the database to use is known through the 'instance' request parameter.
When the method commonEao.getConfiguration(company) is invoked, the first thing that should happen is to create an entity Manager:
#Repository
public final class CommonEao extends AbstractEao
{
public final void getConfiguration(final String company)
{
if (entityManager == null)
{
//I would like to have something here like:
// String instance = springContext.getParameter("instance");
createEntityManager(instance);
}
else ...
}
}
As you can see, when the first time the url is requested, no entityManager exists and it needs to be created based on the instance name provided by the request. Based on the instance name the properties files containing database connection parameters will be used the call the Persistence.createEntityManagerFactory functionality... etc etc... :)
What is the idea? The idea that I had, as you can see in my comments, is to put a parameter in some global context/container that is available for all Spring beans. This idea comes from the JSF world, where you can create a managed bean, annotate it with applicationscope, define a variable in it, and access this variable from any jsf managed bean through injecting the application scoped bean with the managedproperty annotation:
#ManagedBean
public final class SomeJsfBean
{
#ManagedProperty(value = "#{applicationBean}")
private ApplicationBean applicationBean;
private void method()
{
applicationBean.setInstanceName("instance");
}
}
#ManagedBean
public final class AnotherJsfBean
{
#ManagedProperty(value = "#{applicationBean}")
private ApplicationBean applicationBean;
private void method()
{
String instance = applicationBean.getInstanceName();
}
}
I have some restrictions though. I want to use a global object of Spring. I don't have any XML config in my project. Spring is configured like this and nothing more:
#Configuration
#ComponentScan(value = { "megan.fox.is.hot", "as.is.lindsay.lohan" })
public class SpringConfiguration
{
}
I have looked in many places, something I found was fetching a property from PropertyPlaceholderConfigurer and stuff like that, but I didn't understand how it works and mainly it looks way too complex for what i need: just sharing one variable.
There must be an easy solution like in the JSF world, but i suspect i am looking for the wrong name in the Spring world! :)
Any help is greatly appreciated, this is the last thing I need to fix in my project!

Guice and RequestScoped behaviour in multiple threads

I am using Guice's RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a background thread, using the same instances created during request.
However, when I call Provider.get(), guice returns an error:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
afaik, this is due to the fact that Guice uses thread local variables in order to keep track of the current request instances, so it is not possible to call Provider.get() from a thread different from the thread that is handling the request.
How can I get the same instances inside new threads using Provider? It is possible to achieve this writing a custom scope?
I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward #RequestScoped objects, only basic things like the HttpServletResponse. That's because #RequestScoped objects are not expected to be thread safe. You have some options:
If your entire #RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.
You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.
Some of my #RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, #ThreadSafeRequestScoped, and only forwarded those ones.
Code sample:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
#Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
#Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
#Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
#Override
public Boolean visitNoScoping() {
return false;
}
#Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
I have faced the exact same problem but solved it in a different way. I use jOOQ in my projects and I have implemented transactions using a request scope object and an HTTP filter.
But then I created a background task which is spawned by the server in the middle of the night. And the injection is not working because there is no request scope.
Well. The solutions is simple: create a request scope manually. Of course there is no HTTP request going on but that's not the point (mostly). It is the concept of the request scope. So I just need a request scope that exists alongside my background task.
Guice has an easy way to create a request scope: ServletScope.scopeRequest.
public class MyBackgroundTask extends Thread {
#Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
Oh, and you probably will need some injections. Be sure to use providers there, you want to delay it's creation until inside the created scope.
Better use ServletScopes.transferRequest(Callable) in Guice 4

Replacing factory class with CDI

I have a collection of Processor beans in my application along with a factory for creating them.
public abstract class Processor {
public Processor(String config) { .... }
public abstract void process() throws Exception;
}
public class Processor1 extends Processor {
public Processor1(String config) { super(config);..}
public void process() {....}
}
public Processor newProcessor(String impl, String config) {
// use reflection to create processor
}
Can I use CDI to replace the factory class/method? And instead use a #Produces?
I tried using the following to iterate or select the instance I wanted. But Weld tells me that allProcessorInstances.isUnsatisfied() == true. I had to create default no-args ctor in order for Weld to find my Processor subclasses.
#Inject #Any Instance<Processor> allProcessorInstances;
Is there any way to tell the CDI container to use the constructor I want it to use? Or am I thinking about this problem the wrong way?
To use the constructor you'd need to annotate it with #Inject, however, every param on the constructor must itself be a bean or something in the CDI scopes.
Using a producer method and having that take an InjectionPoint as a param, then having your configuration be part of an annotation would work.

Resources