JPA EclipseLink Weaver generates call to porperty getter inside its setter -> NullPointerException - jpa

I have an #Embeddable class that uses property access to wrap another object that's not directly mappable by JPA via field access. It looks like this:
#Embeddable
#Access(AccessType.PROPERTY)
public class MyWrapper {
#NotNull
#Transient
private WrappedType wrappedField;
protected MyWrapper() {
}
public MyWrapper(WrappedType wrappedField) {
this.wrappedField = wrappedField;
}
#Transient
public WrappedType getWrappedField() {
return wrappedField;
}
public void setWrappedField(WrappedType wrappedField) {
this.wrappedField = wrappedField;
}
#Column(name = "wrappedTypeColumn")
protected String getJPARepresentation() {
return wrappedField.toString();
}
protected void setJPARepresentation(String jpaRepresentation) {
wrappedField = new WrappedType(jpaRepresentation);
}
}
Persisting an #Entity with a MyWrapper field works fine. But when I execute a query to load the Entity from the database, I get a NullPointerException. The stacktrace and some debugging shows that Eclipselink creates a new instance of MyWrapper by calling its default constructor and then calls the setJPARepresentation() method (as expected).
But now the unexpected happens: the stacktrace shows that the getJPARepresentation() is called from inside the setter, which then of course leads to a NullPointerException when return wrappedField.toString() is executed.
java.lang.NullPointerException
at MyWrapper.getJPARepresentation(MyWrapper.java:27)
at MyWrapper.setJPARepresentation(MyWrapper.java)
... 109 more
Fact is, there is obviously no call to the getter in the code and the stacktrace shows no line number indicating from where in the setter called the getter. So my conclusion would be, that the bytecode weaver of Eclipselink generated the call to the getter.
It's easy to build a workaround, but my question is: Why does Eclipselink do that?
P.S: I'm using EclipseLink 2.3.2.v20111125-r10461 in a GlassFish Server Open Source Edition 3.1.2 (build 23)

When weaving is enabled (default on Glassfish), EclipseLink will weave code into property get/set methods for,
change tracking
fetch groups (partial objects)
lazy (relationships)
For change tracking support the set method will be weaved to check if the new value is different than the old value, so it must call the get method to get the old value.
Now this is still odd, as since your are building a new object, I would not expect the change listener to be set yet, so would expect the change tracking check to be bypassed. You could decompile the code to see exactly what was generated.
The easiest fix is to just put in a null check in your get method, which is probably best in general for your code. You could also switch to field access, which will not have issues with side-affects in get/set methods. You could also use a Converter to handle the conversion, instead of doing the conversion in get/set methods.

Related

BeanManager always returns same reference

I am creating a custom CDI scope and am using the BeanManager to get an injection of my NavigationHandler custom class. But the beans it returns are quite strange.
So I use the BeanManager that way :
public class ScreenContext implements Context
{
private NavigationHandler getNavigationHandler()
{
final Set<Bean<?>> beans = m_beanManager.getBeans(NavigationHandler.class);
final Bean<?> bean = m_beanManager.resolve(beans);
NavigationHandler reference =
(NavigationHandler) m_beanManager.getReference(bean, NavigationHandler.class,
m_beanManager.createCreationalContext(bean));
System.out.println("Found "+reference+" (hash="+reference.hashCode()+")");
return reference;
}
...
}
I expect, when I use my project using two different browsers, to get two different NavigationHandler, which are defined that way :
#Named
#WindowScoped
public class NavigationHandler
implements Serializable, INavigationHandlerController
But my debugger returns true when I test reference1==reference2. I also get strange hash codes :
Found NavigationHandler#593e785f (hash=1261587818)
Found NavigationHandler#b6d51bd (hash=1261587818)
I don't understand why the hashes used in the toString() are different, but the hash used in hashCode() are the same.
I think I figured out the reason for these two linked problems, that was a tricky one !
m_beanManager.getReference(..) does not return the NavigationHandler instance, but a proxy which is supposed to select and act as the correct NavigationHandler among the existing ones in the scope's context.
Link to understand the concept of Proxy/Context/BeanManager: https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies
So my getNavigationHandler() method is not suited for the work : my pool which calls this method will hold NavigationHandler proxies instead of NavigationHandlers. Because my pool is not an #Injected field, the proxy will not get automatically updated by CDI, hence the reference returned is always the one from the last context actively used by a proxy.
For the same reason in this output:
Found NavigationHandler#593e785f (hash=1261587818)
Found NavigationHandler#b6d51bd (hash=1261587818)
In one case I get the hash of the NavigationHandler instance, and in the other case I get the hash of the NavigationHandler's proxy. Yet I don't know which one is which. I am willing to believe the proxy's toString() is used, as beanManager.getReference(..) is supposed to serve a new proxy each time, and the hashCode is supposed to be practically unique for object each instances.
Link that says every instance's hashcode is unique hashcode and cannot change over time: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode%28%29
So the correct way to implement getNavigationHandler() is:
private getNavigationHandlergetgetNavigationHandler()
{
final Set<Bean<?>> beans = m_beanManager.getBeans(getNavigationHandler.class);
final Bean<?> bean = m_beanManager.resolve(beans);
/* Works : pure reference (not proxied) */
Class<? extends Annotation> scopeType = bean.getScope();
Context context = m_beanManager.getContext(scopeType);
CreationalContext<?> creationalContext = m_beanManager.createCreationalContext(bean);
// Casts below are necessary since inheritence does not work for templates
getNavigationHandler reference =
context.get((Bean<NavigationHandler>) bean, (CreationalContext<NavigationHandler>) creationalContext);
return reference;
}
Link that explains the difference between beanManager.getReference(..) and beanManager.getContext(..).get(..): Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()

DI and inheritance

Another question appeared during my migration from an E3 application to a pure E4.
I got a Structure using inheritance as in the following pic.
There I have an invocation sequence going from the AbstractRootEditor to the FormRootEditor to the SashCompositeSubView to the TableSubView.
There I want to use my EMenuService, but it is null due to it can´t be injected.
The AbstractRootEditor is the only class connected to the Application Model (as a MPart created out of an MPartDescriptor).
I´d like to inject the EMenuService anyway in the AbstractSubView, otherwise I would´ve the need to carry the Service through all of my classes. But I don´t have an IEclipseContext there, due to my AbstractSubView is not connected with Application Model (Do I ?).
I there any chance to get the service injected in the AvstractSubView?
EDIT:
I noticed that injecting this in my AbstractSubView isn´t possible (?), so I´m trying to get it into my TableSubView.
After gregs comment i want to show some code:
in the AbstractRootEditor:
#PostConstruct
public final void createPartControl(Composite parent, #Active MPart mPart) {
...
ContextInjectionFactory.make(TableSubView.class, mPart.getContext());
First I got an Exception, saying that my TableSubView.class got an invalid constructor, so now the Constructor there is:
public TableSubView() {
this.tableInputController=null;
}
as well as my Field-Injection:
#Inject EMenuService eMenuService
This is kind of not working, eMenuService is still null
If you create your objects using ContextInjectionFactory they will be injected. Use:
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
where context is an IEclipseContext (so you have to do this for every class starting from one that is injected by Eclipse).
There is also a seconds version of ContextInjectionFactory.make which lets you provide two contexts the second one being a temporary context which can contain additional values.

JPA Strange behaivor when updating embeddable

My problem is when iam trying to update an object with an embeddable class. If i watch the values, it seems the embeddable values are there. But the code throw an exception telling that that values are empty. And when i watch in the debugger, the object has de values but when i inspect the content in the exception, the object seems not having the values.
public abstract class ItemOrcamento extends EntidadeAuditavel {
#Embedded private ConfiguracaoColeta configuracaoColeta = new ConfiguracaoColeta();
}
And after the em.flush() it throws the exception InvalidStateException and when i search to look for the variables its appears this:

eclipse null analysis field initialization

Using the Null Analysis of Eclipse:
It it possible to define other methods as initializing methods than Constructors?
I have a class like this:
public class Foo {
#NonNull
private Object fooObject;
public Foo() {
super();
}
public void onCreate() {
fooObject = //Something which is not available in the Constructor;
}
Here i get the warning that the NonNull field may has not been initialized. Is there any possibility to kind of declare the init-method as an initalizing one?
I could use #SuppressWarnings("null") for the constructor. But then I ignore all fields, which may instanciated somewhere.
Second chance i see is to make fooObject as #Nullable - but then i need check for null each time i use fooObject.
So is there any better solution?
Null-checking object initialization beyond the constructor is inherently difficult. Several sophisticated approaches exist, all of which require additional annotations.
In your example it seems to be near-impossible, to prove to the compiler, that onCreate() is always called before accessing the field.
A weaker solution has been proposed: #LazyNonNull, an annotation to be used on fields that are initially null, but once initialized can never go back to null. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=414237
Obviously, a static factory method, that gathers all necessary values before invoking a constructor (with arguments) would be a lot easier to get right.

GIN #Inject on variable for Rpc Services

I'm a bit lost with the use of Inject on variable.
I got this code working :
private XXServiceAsync xxServiceAsync;
#Inject
protected IndexViewImpl(EventBus eventBus, XXServiceAsync tableManagementServiceAsync) {
super(eventBus, mapper);
this.xxServiceAsync = xxServiceAsync;
initializeWidgets();
}
With this code, I can call my RPC service wherever I need in the class (On click ...)
I would like to clear a bit the code by injecting direcly in the variable ; doing so :
#Inject
private XXServiceAsync xxServiceAsync;
protected IndexViewImpl(EventBus eventBus) {
super(eventBus, mapper);
initializeWidgets();
}
This always keep the Service to NULL.
Am I doing something wrong ? Is the GIN magic with rpc services meant to be done otherwise?
Thanks!
It is still null at that point, because Gin (and Guice, and other frameworks like this) cannot assign the fields until the constructor has finished running.
Consider how this would look if you were manually wiring the code (remember that Gin/Guice will cheat a little to assign private fields, call non-visible methods):
MyObject obj = new MyObject();//initializeWidgets() runs, too early!
obj.xxServiceAsync = GWT.create(xxService.class);
If you need something in the constructor, pass it into the constructor. If you wont need it right away (such as until asWidget() is called), then a field or setter annotated with #Inject can be helpful.
If you have field level injection you can use an empty #Inject method to do your post-inject initialization. The no-arg injected method will be run after field injections on the class are complete.
#Inject void initialize(){
...
initializeWidgets()
}
Edit: I previously stated that it was run after method injection as well, but testing shows that this is not always the case.