Infinite loop when using wicket-guice - java

im using wicket since a couple of months now and i started to evluate wicket-guice recently.
So im quite a guice noobie :)
Every page got a ServiceClass (lets call it DoService) which manages a number of Objects (i.e. User) ...
Those objects also got an reference to that ServiceClass for some reasons.
public class page ... {
#Inject
private DoService doService;
}
public class DoService ... {
private Collection<User> ...
}
public class User {
#Inject
private DoService doService;
}
Im not quite sure, but i think the following exception occurs cause of the circular references of dependencies though i thought guice manages this all by itsself.
Whatever.....if you need more information to understand my problem pls ask :)
Thanks in advance
java.lang.StackOverflowError
at java.lang.reflect.InvocationTargetException.<init>(InvocationTargetException.java:54)
at WICKET_....DoService$$FastClassByCGLIB$$ce256f9.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.apache.wicket.proxy.LazyInitProxyFactory$CGLibInterceptor.intercept(LazyInitProxyFactory.java:317)
at WICKET_....DoService$$EnhancerByCGLIB$$d1f8934e.rollback(<generated>)
at WICKET_c....DoService$$FastClassByCGLIB$$ce256f9.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
......

I think your design is incorrect: a domain object should not contain references to services. You indeed have a circular dependency.

What Guice does here is to create a new User instance for every DoService instance and a new DoService instance for every User instance. I don't think that's what you want to archive here (apart from the questionable design).
There are several ways around this issue:
Use appropriate Providers in your module
Use singleton scope in guice
Use guice only for one of these instanciations. Have one object create the other and supply itself to the other's constructor for back-reference.

Related

When and how cglib-proxied component instance is created

I'd like to learn if there are some rules / conditions that a Spring component is wrapped (proxied) by CGLIB. For example, take this case:
#Component
public class TestComponent {
}
#Service
//#Transactional(rollbackFor = Throwable.class)
public class ProcessComponent {
#Autowired
private TestComponent testComponent;
public void doSomething(int key) {
// try to debug "testComponent" instance here ...
}
}
If we let it like this and debug the testComponent field inside the method, then we'll see that it's not wrapped by CGLIB.
Now if we uncomment the #Transactional annotation and debug, we'll find that the instance is wrapped: it's of type ProcessComponent$$EnhancerByCGLIB$$14456 or something like that. It's clearly because Spring needs to create a proxy class to handle the transaction support.
But I'm wondering, is there any way that we can detect how and when does this wrapping happen ? For example, some specific locations in Spring's source code to debug into to find more information; or some documentations on the rules of how they decide to create a proxy.
For your information, I need to know about this because I'm facing a situation where some component (not #Transactional, above example is just for demonstrating purpose) in my application suddenly becomes proxied (I found a revision a bit in the past where it is not). The most important issue is that this'll affect such components that also contain public final methods and another issue (also of importance) is that there must have been some unexpected changes in the design / structure of classes. For these kind of issues, of course we must try to find out what happened / who did the change that led to this etc...
One note is that we have just upgraded our application from Spring Boot 2.1.0RELEASE to 2.1.10RELEASE. And checking the code revision by revision up till now is not feasible, because there have been quite a lot of commits.
Any kind of help would be appreciated, thanks in advance.
You could debug into org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(Class, String, TargetSource).
If any advisor is found, the bean will be proxied.
If you use a #Lookup method injection it will also proxy the component class.

Apache Felix - How to guarantee injecting of dynamic references before an activate method

Here is snippet of intrested case:
We have some configuration class it can have multi instances. It suppose that we supply several configurations in one bundle. It's one scope.
#Service
#Component
public class SampleConfigurationImpl implements SampleConfiguration {
// declaration of some properties, init method and etc...
}
Also we have a service which uses these configurations:
#Service
#Component
public class SampleServiceImpl implements SampleService {
#Reference(
referenceInterface = SampleConfiguration.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
private Map<String, SampleConfiguration> sampleConfigurations = new ConcurrentHashMap<>();
private void bindSampleConfigurations(SampleConfiguration sampleConfiguration) {
sampleConfigurations.put(sampleConfiguration.getName(), sampleConfiguration);
}
private void unbindSampleConfigurations(SampleConfiguration sampleConfiguration) {
sampleConfigurations.remove(sampleConfiguration.getName());
}
#Activate
private void init() {
System.out.println(sampleConfigurations.size());
}
}
So, can I get some guarantees that on invocation of init method all configurations are injected (at least of current bundle)? Maybe there is some alternative way to do this. I understand that another bundles can bring new configurations and it's unreal to get guarantees but it's intrested in case of only one bundle.
On practice it can be case when in init method there are only part of configurations. Especially if it's more difficalt case when you have several types of configuration or one service uses another one which has dynamic references and first service relies on fact that everything is injected.
The most unpleasant is that it can bind/unbind configurations both before and after init method.
Maybe there is some way to guarantee that it bind always after init method...
I'm interested in any information. It will be great to get answer on two questions (guarantees before or after). Probably someone has experience how to resolve such problem and can share with me.
Thanks.
No, not that I know of. What I usually do in that case (depending on your use case, it depends on if your activation code is ok with running multiple times) is to create a 'reallyActivate' method I call both from the regular activate and from the bindSampleConfigurations (+ setting an isActivated flag in activate). Then I can perform some logic every time a new SampleConfiguration gets bound, even if it's after the activation. Does that help for your case?

Accessing Magnolia TemplatingFunctions from inside a controller

Is it possible to serve different experiences depending on whether the user is in edit mode? I've noticed that the following method exists; however it is not static:
info.magnolia.templating.functions.TemplatingFunctions.isEditMode()
Is there a way to access the isEditMode() method from inside a controller? Is an instance of it defined somewhere which can be accessed? I imagine that creating a new instance of the TemplatingFunctions class won't help ...
I've looked at using #Inject; however I keep getting issues on injection of all parameters.
#Inject
public ModelAndView renderView(Model model, Node node, TemplatingFunctions templatingFunctions) throws RepositoryException {
if (templatingFunctions.isEditMode()) {
}
}
When I checked what that method does, I found out that its a combination of two functions.
Components.getComponent(ServerConfiguration.class).isAdmin()
and
aggregationStateProvider.get().isPreviewMode()
It seems that you should be injecting a provider to know if user is in preview mode
Provider<AggregationState> aggregationStateProvider
As a general remark, one may understand if a component is injectable or not from the related modules configuration which is under myModule/src/main/resources/META-INF/mymodule.xml. If a component is listed there, then is it injectable in other classes. For instance you should have no problems injecting a type of TemplatinFunctions because it is indeed defined as;
<component>
<type>info.magnolia.templating.functions.TemplatingFunctions</type>
<implementation>info.magnolia.templating.functions.TemplatingFunctions</implementation>
<scope>singleton</scope>
</component>
Further reading can be found at https://documentation.magnolia-cms.com/display/DOCS/Dependency+injection+and+inversion+of+control
Hope this helps,

Passing state to CDI-container-managed beans

I'm using Spring for this project, but I've had the same problem with Guice as well.
Basically, I have functionality that requires both stateless helpers and state data to operate on.
public class AwesomeDoer {
#Inject
private Helper helper; //stateless
...
public void doAwesome(int state) {
helper.help(state)
}
}
This looks pretty good, until doAwesome has 5 parameters and is being called 1000 times, but 3 of the arguments are the same value every time while a fourth argument might change only a handful of times. Changing the appropriate parameters to fields is the obvious solution. However, this requires you to sacrifice either the CDI management of this class, or else you have to have an initializer or setters to fill in the state after Spring does its thing.
I've usually gotten around this by creating a factory managed by Spring, ie
public class AwesomeFactory {
#Inject
private Helper helper;
public AwesomeDoer getAwesomeDoer(int state) {
return new AwesomeDoer(helper, state);
}
}
But again, this means that my AwesomeDoer is no longer being managed by Spring, and it requires me to write yet another layer of non-business logic. It's also easy to imagine this approach leading to the creation of an AwesomeFactoryFactory, etc, which always makes me die a little on the inside.
So does anybody have a cleaner way of doing this?
You can mark your bean using #Configurable from Spring and create it using new AwesomeDoer and passing the parameters in your constructor. #Configurable makes you create the bean on demand and the bean will be managed by Spring to fire the injections like #Autowired.
More info: Create a bean using new keyword and managed by Spring, check the section at the bottom.

Using guice for a framework with injected classes, proper way to initialize?

I'm trying to write a framework where arbitrary bean classes are injected with classes from my API, and they can interact with both those classes as well have triggered callbacks based on defined annotations. Here's an example bean:
#Experiment
static class TestExperiment {
private final HITWorker worker;
private final ExperimentLog log;
private final ExperimentController controller;
#Inject
public TestExperiment(
HITWorker worker,
ExperimentLog expLog,
ExperimentController controller
) {
this.worker = worker;
this.expLog = expLog;
this.controller = controller;
}
#SomeCallback
void callMeBack() {
... do something
log.print("I did something");
}
}
I'm trying to use Guice to inject these beans and handle the interdependencies between the injected classes. However, I have two problems:
One of the classes I pass in (HITWorker) is already instantiated. I couldn't see how to move this to a Provider without significantly complicating my code. It is also persistent, but not to the Guice-defined session or request scope, so I am managing it myself for now. (Maybe if the other issues are overcome I can try to put this in a provider.)
More importantly, I need a reference to the other injected classes so I can do appropriate things to them. When Guice injects them, I can't access them because the bean class is arbitrary.
Here's some really bad code for what I basically need to do, which I am sure is violating all the proper dependency injection concepts. Note that hitw is the only instance that I need to pass in, but I'm creating the other dependent objects as well because I need references to them. With this code, I'm basically only using Guice for its reflection code, not its dependency resolution.
private void initExperiment(final HITWorkerImpl hitw, final String expId) {
final ExperimentLogImpl log = new ExperimentLogImpl();
final ExperimentControllerImpl cont = new ExperimentControllerImpl(log, expManager);
// Create an experiment instance with specific binding to this HITWorker
Injector child = injector.createChildInjector(new AbstractModule() {
#Override
protected void configure() {
bind(HITWorker.class).toInstance(hitw);
bind(ExperimentLog.class).toInstance(log);
bind(ExperimentController.class).toInstance(cont);
}
});
Object experimentBean = child.getInstance(expClass);
expManager.processExperiment(expId, experimentBean);
// Initialize controller, which also initializes the log
cont.initialize(expId);
expManager.triggerStart(expId);
tracker.newExperimentStarted(expId, hitw, cont.getStartTime());
}
Am I screwed and just have to write my own injection code, or is there a way to do this properly? Also, should I just forget about constructor injection for these bean classes, since I don't know what they contain exactly anyway? Is there any way to get the dependencies if I am asking Guice to inject the bean instead of doing it myself?
For context, I've been reading the Guice docs and looking at examples for several days about this, to no avail. I don't think I'm a complete programming idiot, but I can't figure out how to do this properly!
Your "experiment" seems to be something like a "request" in the sense that it has a defined lifecycle and some associated stuff the experiment can pull in at will.
Therefore I think you should wrap all that into a custom scope as described in the docs about Custom Scopes. This matches your case in several points:
You can "seed" the scope with some objects (your HITWorker)
The lifecycle: do "enter scope" before you setup the experiment and "exit scope" after you finished your work.
Access to "shared" stuff like ExperimentLog and ExperimentController: Bind them to the scope. Then both the framework and the experiment instance can simple #Inject them and get the same instance.

Categories