CDI #Inject Instance #Any - But instance never populated with instances - java

Why does 'instance' never iterate over any implementations? What am I missing?
JBoss EAP 6.3.0.GA (AS 7.4.0.Final-redhat-19)
public interface Simple { }
public class SimpleA implements Simple { public SimpleA() { } }
public class SimpleB implements Simple { public SimpleB() { } }
public class SimpleUser {
#Inject #Any Instance<Simple> instance;
#PostConstruct public void init() {
for (final Simple simple : instance) {
System.out.println(simple);
}
}
}

In case it helps someone else, I also am using Deltaspike 1.5.2 and am running into the same issue (if I remove Deltaspike, I no longer have the problem).
In my case adding producer methods did not solve it. After looking around I BeanProvider which gets around the problem but is far from elegant.
https://deltaspike.apache.org/documentation/core.html#BeanProvider
I had to call
List<MyServiceInterface> myServiceList = BeanProvider.getContextualReferences(MyServiceInterface.class, false, false);
There are probably better ways. I notice Deltaspike turns on a bunch of extensions by default, but couldn't find docs on how to disable the ones I am not using as I suspect one may be causing this issue.

Related

Should I never use #PostConstruct in Spring Boot when I have All Args Constructor?

In out project we don't use setter or filed injection, we use only constructor injection, and I know that both options 1. and 2. may work.
Is it unsafe to work with beans in constructor in that case?
Or spring boot 2+ makes something, and I should better use option 1. instead of 2. I can't imagine case when option 1 will go wrong
#Component
#ConfigurationProperties("config")
public class ServiceConfigProperties {
// .... some code
}
Can be unsafe? - but it looks better
#Component
public class Service {
private boolean skipCheck;
public Service(ServiceConfigProperties configProps) {
this.skipCheck = configProps.isSkipCheck();
}
}
Can't be unsafe?
#Component
public class Service {
private boolean skipCheck;
private ServiceConfigProperties configProps;
public Service(ServiceConfigProperties configProps) {
this.configProps= configProps;
}
#PostConstruct
public void initConfig() {
this.skipCheck= configProps.isSkipCheck();
}
}
With a couple of caveats, interacting with constructor-injected beans inside the constructor is completely safe.

Create bean instance at runtime for interface

i am kind of stuck on a problem with creating beans, or probably i got the wrong intention.. Maybe you can help me solve it:
I got a application which takes in requests for batch processing. For every batch i need to create an own context depending on the parameters issued by the request.
I will try to simplyfy it with the following example:
I receive a request to process in a batch FunctionA which is a implementation for my Function_I interface and has sub-implementation FunctionA_DE and FunctionA_AT
Something like this:
public interface Function_I {
String doFunctionStuff()
}
public abstract class FunctionA implements Function_I {
FunctionConfig funcConfig;
public FunctionA(FunctionConfig funcConfig) {
this.funcConfig = funcConfig;
}
public String doFunctionStuff() {
// some code
String result = callSpecificFunctionStuff();
// more code
return result;
}
protected abstract String callSpecificFunctionStuff();
}
public class FunctionA_DE extends FunctionA {
public FunctionA_DE(FunctionConfig funcConf) {
super(funcConf)
}
protected String callSpecifiFunctionStuff() {
//do some specificStuff
return result;
}
}
public class FunctionA_AT extends FunctionA {
public FunctionA_AT(FunctionConfig funcConf) {
super(funcConf)
}
protected String callSpecifiFunctionStuff() {
//do some specificStuff
return result;
}
}
what would be the Spring-Boot-Way of creating a instance for FunctionA_DE to get it as Function_I for the calling part of the application, and what should it look like when i add FunctionB with FunctionB_DE / FunctionB_AT to my classes..
I thought it could be something like:
PSEUDO CODE
#Configuration
public class FunctionFactory {
#Bean(SCOPE=SCOPE_PROTOTYPE) // i need a new instance everytime i call it
public Function_I createFunctionA(FunctionConfiguration funcConfig) {
// create Function depending on the funcConfig so either FunctionA_DE or FunctionA_AT
}
}
and i would call it by Autowiring the FunctionFactory into my calling class and use it with
someSpringFactory.createFunction(functionConfiguration);
but i cant figure it out to create a Prototype-Bean for the function with passing a parameter.. And i cant really find a solution to my question by browsing through SO, but maybe i just got the wrong search terms.. Or my approach to solve this issue i totally wrong (maybe stupid), nobody would solve it the spring-boot-way but stick to Factories.
Appreciate your help!
You could use Springs's application context. Create a bean for each of the interfaces but annotate it with a specific profile e.g. "Function-A-AT". Now when you have to invoke it, you can simply set the application context of spring accordingly and the right bean should be used by Spring.
Hello everyone and thanks for reading my question.
after a discussion with a friend who is well versed in the spring framework i came to the conclusion that my approach or my favoured solution was not what i was searching for and is not how spring should be used. Because the Function_I-Instance depends on the for the specific batch loaded configuration it is not recommended to manage all these instances as #Beans.
In the end i decided to not manage the instances for my Function_I with spring. but instead i build a Controller / Factory which is a #Controller-Class and let this class build the instance i need with the passed parameters for decision making on runtime.
This is how it looks (Pseudo-Code)
#Controller
public class FunctionController {
SomeSpringManagedClass ssmc;
public FunctionController(#Autowired SomeSpringManagedClass ssmc) {
this.ssmc = ssmc;
}
public Function_I createFunction(FunctionConfiguration funcConf) {
boolean funcA, cntryDE;
// code to decide the function
if(funcA && cntryDE) {
return new FunctionA_DE(funcConf);
} else if(funB && cntryDE) {
return new FunctionB_DE(funcConf);
} // maybe more else if...
}
}

lambda expression prevents class from spring component-scan

Our Application have Class Test with #Component annotation.
Lambda expression is being used here.
#Component
public class Test{
private ScheduledExecutorService schedulerExecutorService;
private long timeoutForRollBack=180000;
private long timeoutFailoverDelay=180000;
public static Test getInstance() {
if (INSTANCE == null) {
/*Actual instance will be created via reflection. using new for understanding */
INSTANCE = new Test();
}
return INSTANCE;
}
public void handleFailOver(){
schedulerExecutorService.scheduleWithFixedDelay(
() -> {
schedulerExecutorService.shutdown();
},
timeoutForRollBack, timeoutFailoverDelay, TimeUnit.MILLISECONDS);
}
}
But this Test class bean is not created. But when this method is commented, then the Test class bean is created.
Using Java 8 oracle and Eclipse Neon2.
Suggest if any changes needed to fix this.
Edit 1:
Found similar issue reported:
https://java.net/jira/browse/JAVASERVERFACES-3732
Edit 2:
Similar issue faced https://github.com/orfjackal/retrolambda/issues/121
P.S:
if
() -> {
schedulerExecutorService.shutdown();
}
is replaced with private innerclass, this is working fine.
private class TerminalScheduledExecutor implements Runnable{
#Override
public void run() {
schedulerExecutorService.shutdown();
}
}.
However looking forward for solutions without replacing lambda functions.
Have you tried to change spring framework's logging level for detailed bean creation logs?
per suggestion here: Question with no answers, but issue solved in the comments (or extended in chat)
Found the solution at last:
Issue was with
org.reflections.Reflections
version. Upgraded it to
0.9.9-RC2
and the issue is resolved.
As per #OnurAktaş suggestions, enabled debug and found that
could not scan file error occurred in org.reflections.reflection.

Inject cached instances using cdi

I want expose instances managed by an external framework to CDI applications using #Inject. These instances must be provided this other framework since their lifecycle is based on various caching strategies.
Ex: same instance is visible within same thread scope, might live across many request scopes, session scope is not applicable. Seems I need to define a new scope targeting these kind of instances?
What is the best way to do this? An extension, is it possible with producer methods?
I almost got it to work with producer methods using the following:
#Inject
#CustomInject
FwObject obj;
#Produces
#CustomInject
FwObject createConfig(InjectionPoint p) {
return (FwObject) ctx.get((Class<?>) p.getType());
}
But this force me to be explicit about the type produced which is not possible since there is no common framework interface.
Any help appreciated.
Maybe with producer methods, all depends on what you need, but an extension is probably the best way to go. If you need to go with a new scope (if you're using JSF the Conversation scope may work) you will certainly need to create an extension.
I think I solved it by creating a custom scope. The following article was really helpful:
http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/
This is a very brief description of how I solved it.
Create custom scope annotation.
import javax.enterprise.context.NormalScope;
#Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
#NormalScope
public #interface CustomScope {
}
Create custom context.
import javax.enterprise.context.spi.Context;
public class CustomContext implements Context {
private MyFw myFw = .... ;
#Override
public Class<? extends Annotation> getScope() {
return CustomScope.class;
}
#Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public <T> T get(Contextual<T> contextual) {
Bean bean = (Bean) contextual;
return (T) myFw.get(bean.getBeanClass());
}
#Override
public boolean isActive() {
return true;
}
}
Create extension and register context.
import javax.enterprise.inject.spi.Extension;
public class CustomContextExtension implements Extension {
public void afterBeanDiscovery(#Observes AfterBeanDiscovery event, BeanManager manager) {
event.addContext(new CustomContext());
}
}
Register extension.
Add CustomContextExtension to META-INF/javax.enterprise.inject.spi.Extension
Add CustomScope to framework object.
#CustomScope
public class FwObject { ... }
Inject FwObject using #Inject where needed.
public class MyService {
#Inject
FwObject obj;
}

wicket #SpringBean can not create bean

I have a project on Eclipse, Wicket, Spring, Hibernate. Every thing works normaly except : when I try
public class SortableContactDataProvider extends SortableDataProvider<User>
{
#SpringBean
private Service service;
public Iterator<User> iterator(int first, int count)
{
//SortParam sp = getSort();
return service.findAllUsers().subList(0, 15).iterator();
}
...
the service variable is null? In any another places when I use this constuction "service" is not null and working well. Please help me to solve this problem.
#SpringBean works only in any Subclass of Component.
You need to do the following in your Constructor
Wicket 1.4
InjectorHolder.getInjector().inject(this);
Wicket 1.5+
org.apache.wicket.injection.Injector.get().inject(this);
See 'generic IDataProvider implementation' # http://stronglytypedblog.blogspot.com/2009/03/wicket-patterns-and-pitfalls-1.html
Enjoy
A bit more of context for those who are newbies to Wicket/Spring environment - as bert, pointed out, #SpringBean works only in any Subclass of Component so you'll need to drive the injection manually. This is a 2 step process:
Drive the injection in your class, something as:
public class SortableContactDataProvider extends SortableDataProvider<User>
{
#SpringBean
private Service service;
public SortableContactDataProvider(){
Injector.get().inject(this); // set up the injection
}
public Iterator<User> iterator(int first, int count)
{
return service.findAllUsers().subList(0, 15).iterator();
}
}
And make sure the Injector is set up in Wicket application - something like:
public WicketApplication
#Override
protected void init() {
// make sure Spring injector is available and set up
getComponentInstantiationListeners().add(new SpringComponentInjector(this));
}
}

Categories

Resources