Java – spring, notreadablepropertyexception and GlassFish versions
I am using a web application using spring MVC
It's in GlassFish 3.0 It worked well on GlassFish 3.1, but it began to behave strangely when migrating to GlassFish 3.1 Some pages are only partially displayed or do not display anything at all, and there are many such messages in the log:
[#|2012-08-30T11:50:17.582+0200|WARNING|glassfish3.1|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=69;_ThreadName=Thread-1;|StandardWrapperValve[SpringServlet]: PWC1406: Servlet.service() for servlet SpringServlet threw exception org.springframework.beans.NotReadablePropertyException: Invalid property 'something' of bean class [com.something.something]: Bean property 'something' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:729) at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:576) at org.springframework.beans.BeanWrapperImpl.getBeanWrapperForPropertyPath(BeanWrapperImpl.java:553) at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:719) at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99) at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:226) at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:178) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:198) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:164) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:127) at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:421) at org.springframework.web.servlet.tags.form.TextareaTag.writeTagContent(TextareaTag.java:95) at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102) at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)
The error message is incorrect because the property in question does not have a setter method (get its value through the constructor) But as I said, use GlassFish 3.0 This is not a problem when using GlassFish 3.1. It will only occur when using it on a new server using GlassFish 3.1
Who knows if there is anything in the GlassFish version that may cause this problem? Or is it some configuration missing from the new server?
Some codes:
controller:
@modelattribute public SomethingContainer retriveSomethingContainer(@PathVariable final long id { return somethingContainerDao.retrieveSomethingContainer(id); } @InitBinder("somethingContainer") public void initBinderForSomething(final WebDataBinder binder) { binder.setAllowedFields(new String[] { "something.title","something.description",}); }
SomethingContainer:
@Embedded private final Something something = new Something(); public Something getSomething() { return something; } //no setter public String getDescription() { return something.getDescription(); }
to update:
Restarting GlassFish can actually solve the problem temporarily I suspect it may be related to the loading of custom binders. We encountered some memory errors. I think it is related to it, but it has been fixed but not solved
Update 2:
At 3.0 1 server, one of the JVM parameters is - client On the 3.1 server, it is - server We change it to - client, which reduces the frequency of errors. It occurs every other day - server, and it takes 2 weeks to happen - client
Update 3:
Some information about the server (more information can be added if requested...)
Server1 (working):
Windows Server 2003 Java jdk 6 build 35 Glassfish 3.0.1 build 22 -xmx 1024m
Server2 (the one with the problem):
Windows Server 2008 64-bit Java jdk 6 build 31 Glassfish 3.1 build 43 -xmx 1088m -xms 1088m
We are using spring 3.1 Version 0
Update 4:
I recreate the error by renaming the field in the JSP to something that does not exist in the modelattribute
But more importantly, I noticed something: the system can't find the field of getter, which is usually the superclass of the field referenced in modelattribute Continuing with my example, somthingcontainer is really like this:
public class SuperSomethingContainer { [...] private Something something; public Something getSomething() { return something; } } public class SomethingContainer extends SuperSomethingContainer { [...] }
The reference in the controller remains the same, so it references the fields in the superclass of the related object
Update 5:
After an error occurred, I tried to connect to the production server using the debugger I put a breakpoint on the return statement of a controller method, returned an object with an error, and tried to see if the field could be accessed at that time I can, so the problem must be in spring MVC / generated JSP classes
(in addition, the wrong field is of type "someobject. Something [0]. Somethingelse [0]", but when somethingelse list is empty, there is no error! For me, this means that it cannot find the get method of the list (?) to some extent.)
Update 6:
It seems that the problem is related to generating Java classes from JSPS We do not use precompiled JSPS when deploying, so they will be compiled when we use them for the first time The first time you visit the page, you will have problems and compile the JSP I have also noticed that once there is a problem, the compiled JSPS will make mistakes I keep some java files generated by the problem, and I will compare them with the working file when I restart next time Getting closer:)
Update 7:
There is no difference between the compiled JSP java file causing the error and the uncompiled JSP java file So I left a little
So, I now know that Java objects leaving the controller are good (checked with the debugger), and Java classes generated from JSP are good So it has to be somewhere in between. Now I need to find out what
Update 8:
Another round of debugging and reducing the problem It turns out that spring caches attributes belonging to various classes At org springframework. beans. In beanwrapperimpl, the method getpropertyvalue has the following contents:
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException { String propertyName = tokens.canonicalName; String actualName = tokens.actualName; PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); if (pd == null || pd.getReadMethod() == null) { throw new NotReadablePropertyException(getRootClass(),this.nestedPath + propertyName); }
The problem is that cached introspectionresults does not contain the property in question, but it contains all other properties of the class More will need to be dug to try to find out why it was lost, if it was lost from the beginning, or if it was lost somewhere
In addition, I noticed that the missing properties are those that have no setter but only getter Also, it seems to be context aware, as shown by the stack trace Therefore, the fact that a property cannot be found when accessing one page does not mean that it is unavailable when accessing another page
Update 9:
Another day, more debugging In fact, I found some good things The call to getcachedintrospectionresults() in the previous code block was injured by calling cachedintrospectionresults #forclass (theclassinquestion) This returns a cachedintrospectionresults object that far exceeds all expected properties (11 of 21) After entering the forclass method, I found that:
static CachedIntrospectionResults forClass(Class beanClass) throws BeansException { CachedIntrospectionResults results; Object value = classCache.get(beanClass); if (value instanceof Reference) { Reference ref = (Reference) value; results = (CachedIntrospectionResults) ref.get(); } else { results = (CachedIntrospectionResults) value; } if (results == null) { //build the CachedIntrospectionResults,store it in classCache and return it.
It turns out that the returned cachedintrospectionresults are generated by classcache Get (beanclass) Therefore, the content stored in the classcache is corrupted / does not contain all the content it should contain I'm in classcache Put a breakpoint on get (beanclass) - line and try to run it through the debugger:
When the method is allowed to complete and rebuild cached introspectionresults, things begin to work again Therefore, if you allow it to be rebuilt, the content stored in the classcache is out of sync with the content to be created Is this due to a problem during the first build, or if the classcache is broken somewhere on the line I don't know at present
I began to suspect that this was related to the classloader, because the problem I encountered before was due to the change in the working mode of the classloader when updating GlassFish
Solution
There may be many possible reasons I'm not sure about the actual situation, but I can give you a way to find out the problem
Step 1: in GlassFish 3.0 The application is deployed on the server 2 machine on build 22. Now, if it works normally on the server 2 machine, it means that there may be a problem with the glass fish library. The following may be the reason for this problem
> Glassfish 3.0. Any libraries missing from GlassFish 3.1 version 43 in version 1 You can solve this problem by copying all libraries from the GlassFish server to the new server. > I'm GlassFish. The library conflicts with the spring version [similliar, some problems I faced in tomcat, it was useful to me when I replaced my spring library from 3.0.1 to 3.0.3], so replace your spring library with the latest library
Step 2: if the result of step 1 is that the application is not in GlassFish 3.0 1Build 22 runs on server 2. There may be the following reasons
>If any libraries you pasted on Java lib are not included in this server machine or have different versions. > Any folder that sets or uses any environment variable on server 1 on the classpath does not exist on server 2, or there is no jar or jar with diff version