Nestor Urquiza opened SPR-8441 and commented
Hi,
I am trying to integrate jpasecurity project and I think we have found a bug in GenericConversionService#findConverterForClassPair(TypeDescriptor sourceType, TypeDescriptor targetType).
Basically classQueue accumulates all possible classes that Spring will try to find a converter for. Instead of accumulating java.lang.Object as one of the possibilities it stores jpasecurity SecureObject because that is the inmediate superclass of the secured JPA Entity. Once it cannot find a converter it will cache that situation forever like this key:
ConverterCacheKey [sourceType = [TypeDescriptor com.nestorurquiza.model.InstrumentTraded$$EnhancerByCGLIB$$114fa3ec], targetType = [TypeDescriptor java.lang.String]]=NO_MATCH
From that moment on it will never rescan to find a converter. I use Binding to make my JSP list the content of the particular entity but the page will never render complete (it starts rendering but an exception will be triggered whenever the object is attempted to be bound in the JSP)
You can find the whole thread in https://sourceforge.net/projects/jpasecurity/forums/forum/790334/topic/4563054.
Thanks! -Nestor Urquiza
Affects: 3.0.4, 3.0.5, 3.1 M1, 3.1 M2
Reference URL: https://sourceforge.net/projects/jpasecurity/forums/forum/790334/topic/4562571/index/page/1
Comment From: spring-projects-issues
Keith Donald commented
We do check the entire entire hierarchy. So if your InstrumentedObject extends SecureObject, we will check InstrumentedObject -> SecureObject -> java.lang.Object. I'm not sure why you think we don't do this. The issue is there is no default converter that knows how to convert a InstrumentedObject (or any of its super classes) to a String. You can resolve this by registering your own converter that does this. You could implement a annotation-driven converter that applies to all @Entity
objects that does this.
Comment From: spring-projects-issues
Keith Donald commented
You could also trigger the existing FallbackObjectToStringConverter by defining a InstrumentedObject(String) or InstrumentedObject.valueOf(String) method. In this way no custom converter would be needed on your part.
Comment From: spring-projects-issues
Nestor Urquiza commented
Hi Keith,
Thanks for looking at this. I have made the jpasecurity group aware of this response at https://sourceforge.net/projects/jpasecurity/forums/forum/790334/topic/4601087
I do have my own converter and with that I am able to work around the issue that apparently is at jpasecurity level and not really spring according to what you see.
Thanks again, -Nestor
Comment From: spring-projects-issues
Nestor Urquiza commented
Hi Keith,
Arne (the jpasecurity author) challenged me with some questions and comments in the link above so I follow your/his suggestions and here is what I have found:
- I used a custom convertor as I said to work around the issue. So using it I do not need to annotate individual entities but all of them will get automatically covered by that convertor. So yes the List of entities were rendered but if you tae a look at the convertor code the entity would be presented with the result of the toString() method. However that method is not implemented so I really do not know how the taglib was actually rendering the real name of the entity after all.
\
public class SecureObjectToStringConverter implements Converter\
@Override
public String convert(SecureObject source) {
return (source != null ? source.toString() : null);
}
} \
-
I still do not know if this is a Spring issue or not but one thing for sure is without a convertor, no constructor, non valueOf methods when not using jpasecurity I get no complains from JSP and the list is rendered as expected. As soon as I add jpasecurity to my project that rendering fails with the details you can see from the link I posted before. This is the part we do not understand as you can see from the latest post in the discussion link I provided.
-
You said you do not understand why I said the hierarchy was not explored to upper parents and just to the immediate parent. That is perhaps a wrong conclusion but granted I did see the code not iterating more after it found the SecureObject as I described in this thread. I understand though you cannot reproduce perhaps with a junit test as this comes from JSP. Here are the relevant lines:
\
\
4. Let me just confirm that when I added the constructor accepting the name of the entity the code did not fail and actually that is going to be from now on my workaround: Ensure that all Entities have a constructor with the name. Not sure how this will affect the rest of the project but I will try to push the team towards that to avoid the use of SecureObjectToStringConverter.
- I am using spring 3.0.4.RELEASE just in case that matters.
Thanks, -Nestor
Comment From: aaaaarrrgghh
Hello, I've run into this issue - what was the resolution here?
This error happens on ALL of my entities that have @ManyToOne
properties. The error has started after I added the Spring Security - but only after doing Step 3, not before that.
1) Adding the spring-boot-starter-security dependency
2) Adding user.name
and user.password
to application.properties (works till this step with http basic authentication)
3) Adding aSecurityConfig
class that extends WebSecurityConfigurerAdapter
. As soon as I do this step, the error starts.
//the problem collection
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "BELONGSTOCATEGORY", nullable = false)
@EntityFormat("#{categoryName}")
private Category belongsToCategory;
the error trace (top half)
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [@javax.persistence.ManyToOne @javax.persistence.JoinColumn @io.springlets.format.EntityFormat **com.XXX.model.Category**] to type [java.lang.String]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313) ~[spring-core-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-4.3.3.RELEASE.jar:4.3.3.RELEASE]
at io.springlets.data.web.datatables.ConvertedDatatablesData.convertProperty(ConvertedDatatablesData.java:188) ~[springlets-data-commons-1.2.0.RELEASE.jar:1.2.0.RELEASE]
at io.springlets.data.web.datatables.ConvertedDatatablesData.convert(ConvertedDatatablesData.java:165) ~[springlets-data-commons-1.2.0.RELEASE.jar:1.2.0.RELEASE]
at io.springlets.data.web.datatables.ConvertedDatatablesData.convertAll(ConvertedDatatablesData.java:128) ~[springlets-data-commons-1.2.0.RELEASE.jar:1.2.0.RELEASE]
at io.springlets.data.web.datatables.ConvertedDatatablesData.<init>(ConvertedDatatablesData.java:112) ~[springlets-data-commons-1.2.0.RELEASE.jar:1.2.0.RELEASE]
at io.springlets.data.web.datatables.ConvertedDatatablesData.<init>(ConvertedDatatablesData.java:74) ~[springlets-data-commons-1.2.0.RELEASE.jar:1.2.0.RELEASE]
at **com.XXX.web.CategoriesItemTagsSetThymeleafController.datatables(CategoriesItemTagsSetThymeleafController.java:252) ~[classes/:na]**
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]