Bean property being set to null by Editor framework even though it cannot be null

101 views
Skip to first unread message

Tiago Rinck Caveden

unread,
Jun 1, 2012, 4:39:01 AM6/1/12
to google-we...@googlegroups.com
Hello all,

I have a bean of type A which contains a property of type X which is a JaxB bean (annotated with @XmlRootElement).
I'm editing this being with the help of an Editor<A>.

One of the properties of X is a Boolean which is initialized as Boolean.FALSE on construction. This property is is annotated with @XmlElement(required=true).
I do not care about this property in my Editor - it is supposed to be used only by the back-end. So I don't define any sub-editor to handle it. I just ignore it.

I use the Editor to create a new instance of A. Both A and X are created via RequestContext.create().

When I submit my modifications to the server, I have the exception copied below. I've put a breakpoint on ReflectiveServiceLayer.setProperty, on the line which calls setter.invoke, and verified that the exception is thrown precisely when the framework tries to attribute 'null' as value to the Boolean property which I mentioned above. That property may not be null.

Is this a bug in the framework, or am I doing something wrong? Am I supposed to create sub-editors for every property of the edited entity?

Here is the exception:

Jun 1, 2012 10:21:20 AM com.google.web.bindery.requestfactory.server.RequestFactoryServlet doPost
SEVERE: Unexpected error
java.lang.IllegalArgumentException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.web.bindery.requestfactory.server.ReflectiveServiceLayer.setProperty(ReflectiveServiceLayer.java:234)
at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.setProperty(ServiceLayerDecorator.java:193)
at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.setProperty(ServiceLayerDecorator.java:193)
at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.setProperty(ServiceLayerDecorator.java:193)
at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor$1.visitValueProperty(SimpleRequestProcessor.java:541)
at com.google.web.bindery.autobean.vm.impl.ProxyAutoBean.traverseProperties(ProxyAutoBean.java:289)
at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:166)
at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.accept(AbstractAutoBean.java:101)
at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor.processOperationMessages(SimpleRequestProcessor.java:516)
at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor.process(SimpleRequestProcessor.java:210)
at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor.process(SimpleRequestProcessor.java:127)
at com.google.web.bindery.requestfactory.server.RequestFactoryServlet.doPost(RequestFactoryServlet.java:133)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1097)
at fr.extelia.smdt.www.server.HttpHeadersFilter.doFilter(HttpHeadersFilter.java:64)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1088)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1088)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
[ERROR] 500 - POST /gwtRequest (127.0.0.1) 49595 bytes
   Request headers
      Host: 127.0.0.1:8888
      Connection: keep-alive
      User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/11.10 Chromium/18.0.1025.168 Chrome/18.0.1025.168 Safari/535.19
      Accept: */*
      Accept-Encoding: gzip,deflate,sdch
      Accept-Language: en-US,en;q=0.8,fr-FR;q=0.6,fr;q=0.4,es-419;q=0.2,es;q=0.2,pt-BR;q=0.2,pt;q=0.2
      Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
      Cookie: JSESSIONID=bq6wfphki10f
      Content-Length: 681
      Origin: http://127.0.0.1:8888
      Content-Type: application/json; charset=UTF-8
      X-GWT-Permutation: HostedMode
   Response headers
      Content-Type: text/html; charset=utf-8


Thank you for any help.

Best regards,
--
Tiago Rinck Caveden

Thomas Broyer

unread,
Jun 1, 2012, 4:51:00 AM6/1/12
to google-we...@googlegroups.com
Is X an EntityProxy or a ValueProxy? If it's a ValueProxy, then this is the expected behavior; you'll have to either:
  • allow 'null' in your setter (you could treat it as a Boolean.FALSE if you like)
  • set the property value to Boolean.FALSE on the client-side
  • change your property type from 'Boolean' to 'boolean': there's little to no reason to use 'Boolean' if you disallow 'null', just use 'boolean' instead.

Tiago

unread,
Jun 1, 2012, 4:51:58 AM6/1/12
to google-we...@googlegroups.com
Just for the record, if I manually set the problematic property before handling the new proxy to the editor framework, everything works fine.


On Friday, June 1, 2012 10:39:01 AM UTC+2, Tiago wrote:

Thomas Broyer

unread,
Jun 1, 2012, 4:52:04 AM6/1/12
to google-we...@googlegroups.com


On Friday, June 1, 2012 10:51:00 AM UTC+2, Thomas Broyer wrote:
Is X an EntityProxy or a ValueProxy? If it's a ValueProxy, then this is the expected behavior; you'll have to either:
  • allow 'null' in your setter (you could treat it as a Boolean.FALSE if you like)
  • set the property value to Boolean.FALSE on the client-side
  • change your property type from 'Boolean' to 'boolean': there's little to no reason to use 'Boolean' if you disallow 'null', just use 'boolean' instead.
I forgot to mention: if you don't care about the property on the client-side at all, then you're not forced to map it into your proxy either; that'd solve the problem too.

Tiago

unread,
Jun 1, 2012, 6:31:42 AM6/1/12
to google-we...@googlegroups.com
Hello Thomas,

On Friday, June 1, 2012 10:51:00 AM UTC+2, Thomas Broyer wrote:
Is X an EntityProxy or a ValueProxy? If it's a ValueProxy, then this is the expected behavior; you'll have to either:

It's a ValueProxy (X is not an entity).
Are you sure that an IllegalArgumentException with no message coming from a native method I didn't call directly is an expected behavior?
Shouldn't the framework just let the value defined in the constructor of the domain object, or, if that's too complicated, try raising a better exception?
 
  • set the property value to Boolean.FALSE on the client-side
I went for that one. You're right that it could be boolean though. It's just that in this project every domain property is a Boolean, never a boolean.
 
Also, I must declare the property in the proxy because, although the Editor I mention doesn't care about it, there are some points where I need to read the value of this property in the client-side.

Thank you very much for the quick answer.

Thomas Broyer

unread,
Jun 1, 2012, 7:15:17 AM6/1/12
to google-we...@googlegroups.com


On Friday, June 1, 2012 12:31:42 PM UTC+2, Tiago wrote:
Hello Thomas,

On Friday, June 1, 2012 10:51:00 AM UTC+2, Thomas Broyer wrote:
Is X an EntityProxy or a ValueProxy? If it's a ValueProxy, then this is the expected behavior; you'll have to either:

It's a ValueProxy (X is not an entity).
Are you sure that an IllegalArgumentException with no message coming from a native method I didn't call directly is an expected behavior?

Yes.
  1. You create a ValueProxy, all its properties are 'null' by default
  2. You send it to the server; because it's a ValueProxy, all its properties have to be sent, so the unset property is sent with a 'null' value
  3. The RequestfactoryServlet / SimpleRequestProcessor creates a domain object and pushes the property values in it, so it tries to set the property to 'null'.
I think it's been suggested somewhere that we add the concept of "default values" to AutoBean and RF proxy properties, so you could annotate your X proxy to have the property default to some specific value, without the need to set it explicitly before sending it to the server. I can't find the enhancement request back (it does not seem to be in the issue tracker at least).
 
Shouldn't the framework just let the value defined in the constructor of the domain object,

No. Not for a ValueProxy.
 
or, if that's too complicated, try raising a better exception?

Well, it's your exception AFAICT.

  • set the property value to Boolean.FALSE on the client-side
I went for that one. You're right that it could be boolean though. It's just that in this project every domain property is a Boolean, never a boolean.
 
Also, I must declare the property in the proxy because, although the Editor I mention doesn't care about it, there are some points where I need to read the value of this property in the client-side.

You can have several proxy interfaces for the same domain object; if that can help in your case.
Reply all
Reply to author
Forward
0 new messages