Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RestBuilder default constructor breaks JSON converters/marshallers since 6.0.5 #864

Closed
benorama opened this issue Feb 3, 2017 · 15 comments
Milestone

Comments

@benorama
Copy link

benorama commented Feb 3, 2017

Steps to Reproduce

  1. Add compile 'org.grails:grails-datastore-rest-client' dependency
  2. Define a restBuilder(RestBuilder) bean in your spring resources.groovy
  3. Try to use JSON marshalling (ex.: as JSON)

Expected Behaviour

It should render JSON.

Actual Behaviour

It throws a StringIndexOutOfBoundsException exception.

Environment Information

  • Operating System: Mac OSX 10.12.3
  • Grails Version: 3.2.5
  • JDK Version: 1.8.0_25

Example Application

@benorama
Copy link
Author

benorama commented Feb 4, 2017

This is probably linked to #825 and #536

@graemerocher
Copy link
Member

Can probably be worked around by simply using new RestBuilder() instead of a bean, but yes I agree not great

@benorama
Copy link
Author

benorama commented Feb 9, 2017

We were using new RestBuilder() and it was also messing up our JSON marshallers.

Our workaround is to duplicate the RestBuilder class in our own package and removing from the constructor:

def currentConfiguration = ConvertersConfigurationHolder.getConverterConfiguration(JSON)
if(currentConfiguration instanceof DefaultConverterConfiguration) {
    // init manually
    DefaultConverterConfiguration defaultConfig = ((DefaultConverterConfiguration)currentConfiguration)
    defaultConfig.registerObjectMarshaller(new MapMarshaller())
    defaultConfig.registerObjectMarshaller(new ArrayMarshaller());
    defaultConfig.registerObjectMarshaller(new ByteArrayMarshaller());
    defaultConfig.registerObjectMarshaller(new CollectionMarshaller());
    defaultConfig.registerObjectMarshaller(new GroovyBeanMarshaller());
}

It solves the issue on our apps.

@graemerocher graemerocher added this to the 6.0.8 milestone Feb 9, 2017
@benorama
Copy link
Author

benorama commented Feb 9, 2017

If it can help, when turning on grails.converters.default.circular.reference.behaviour = "EXCEPTION" I've got this exception when using JSON marshaller/converters on a simple Map:

org.grails.web.converters.exceptions.ConverterException: Circular Reference detected: class java.util.LinkedHashMap
        at grails.converters.JSON.handleCircularRelationship(JSON.java:354)
        at grails.converters.JSON.value(JSON.java:176)
        at grails.converters.JSON.convertAnother(JSON.java:144)
        at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:67)
        at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:39)
        at grails.converters.JSON.value(JSON.java:184)
        at grails.converters.JSON.convertAnother(JSON.java:144)
        at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:67)
        at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:39)
        at grails.converters.JSON.value(JSON.java:184)
        at grails.converters.JSON.convertAnother(JSON.java:144)
        at org.grails.web.converters.marshaller.json.MapMarshaller.marshalObject(MapMarshaller.java:45)
        at org.grails.web.converters.marshaller.json.MapMarshaller.marshalObject(MapMarshaller.java:30)
        at grails.converters.JSON.value(JSON.java:184)
        at grails.converters.JSON.render(JSON.java:119)
        at org.grails.web.converters.AbstractConverter.toString(AbstractConverter.java:109)

@jameskleeh jameskleeh changed the title RestBuilder default constructor brakes JSON converters/marshallers since 6.0.5 RestBuilder default constructor breaks JSON converters/marshallers since 6.0.5 Feb 14, 2017
@jameskleeh
Copy link
Contributor

jameskleeh commented Feb 14, 2017

The issue is caused because the GroovyBeanMarshaller is failing to marshal a org.grails.config.NavigableMap$NullSafeNavigator. The marshaller that is intended for maps should be used instead. I think it's an ordering issue

@jameskleeh
Copy link
Contributor

Fixed by 0be3bea

@sarbogast
Copy link

@jameskleeh FYI, Jeff's solution meant changing a lot of my tests to make them work with the API of this other RxRestBuilder thingy. So instead I went with @benorama's workaround and injected the solution in 0be3bea, and I got 15 out of 18 tests to pass again. The other 3 fail with another JSON related exception:

java.lang.RuntimeException: org.grails.web.converters.exceptions.ConverterException: Error converting Bean with class org.springframework.beans.GenericTypeAwarePropertyDescriptor
	at org.grails.web.converters.AbstractConverter.toString(AbstractConverter.java:111)
	at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:628)
	at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:575)
	at org.codehaus.groovy.runtime.InvokerHelper.toString(InvokerHelper.java:130)
	at org.codehaus.groovy.runtime.DefaultGroovyMethods.toString(DefaultGroovyMethods.java:13696)
	at grails.artefact.controller.support.ResponseRenderer$Trait$Helper.render(ResponseRenderer.groovy:256)
	at grails.artefact.controller.support.ResponseRenderer$Trait$Helper$render$1.call(Unknown Source)

I'll continue to investigate.

@jameskleeh
Copy link
Contributor

@sarbogast Feel free to open a new issue with a sample project in grails-data-mapping

@sarbogast
Copy link

The root cause seems to be way deeper than that and it's harder to identify what's causing it. But I'll try:

java.lang.IllegalAccessException: Class org.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller can not access a member of class org.springframework.beans.GenericTypeAwarePropertyDescriptor with modifiers "public"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Method.invoke(Method.java:490)
	at org.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller.marshalObject(GenericJavaBeanMarshaller.java:48)
	at org.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller.marshalObject(GenericJavaBeanMarshaller.java:34)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.ArrayMarshaller.marshalObject(ArrayMarshaller.java:41)
	at org.grails.web.converters.marshaller.json.ArrayMarshaller.marshalObject(ArrayMarshaller.java:30)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller.marshalObject(GenericJavaBeanMarshaller.java:50)
	at org.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller.marshalObject(GenericJavaBeanMarshaller.java:34)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:67)
	at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:39)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:67)
	at org.grails.web.converters.marshaller.json.GroovyBeanMarshaller.marshalObject(GroovyBeanMarshaller.java:39)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.CollectionMarshaller.marshalObject(CollectionMarshaller.java:41)
	at org.grails.web.converters.marshaller.json.CollectionMarshaller.marshalObject(CollectionMarshaller.java:30)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.MapMarshaller.marshalObject(MapMarshaller.java:45)
	at org.grails.web.converters.marshaller.json.MapMarshaller.marshalObject(MapMarshaller.java:30)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.CollectionMarshaller.marshalObject(CollectionMarshaller.java:41)
	at org.grails.web.converters.marshaller.json.CollectionMarshaller.marshalObject(CollectionMarshaller.java:30)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.convertAnother(JSON.java:144)
	at org.grails.web.converters.marshaller.json.MapMarshaller.marshalObject(MapMarshaller.java:45)
	at org.grails.web.converters.marshaller.json.MapMarshaller.marshalObject(MapMarshaller.java:30)
	at grails.converters.JSON.value(JSON.java:184)
	at grails.converters.JSON.render(JSON.java:119)
	at org.grails.web.converters.AbstractConverter.toString(AbstractConverter.java:109)
	at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:628)
	at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:575)
	at org.codehaus.groovy.runtime.InvokerHelper.toString(InvokerHelper.java:130)
	at org.codehaus.groovy.runtime.DefaultGroovyMethods.toString(DefaultGroovyMethods.java:13696)
	at grails.artefact.controller.support.ResponseRenderer$Trait$Helper.render(ResponseRenderer.groovy:256)
	at grails.artefact.controller.support.ResponseRenderer$Trait$Helper$render$1.call(Unknown Source)
	at com.adessa.unbox.api.employee.EmployeeImportController.render(EmployeeImportController.groovy)
	at grails.artefact.controller.support.ResponseRenderer$render.callCurrent(Unknown Source)
	at com.adessa.unbox.api.employee.EmployeeImportController.importEmployees(EmployeeImportController.groovy:37)
	at com.adessa.unbox.api.employee.EmployeeImportController.importEmployees(EmployeeImportController.groovy)
	at org.grails.core.DefaultGrailsControllerClass$MethodHandleInvoker.invoke(DefaultGrailsControllerClass.java:222)
	at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:187)
	at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:651)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at javax.servlet.FilterChain$doFilter.call(Unknown Source)
	at grails.plugin.springsecurity.rest.RestLogoutFilter.doFilter(RestLogoutFilter.groovy:80)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:105)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at javax.servlet.FilterChain$doFilter.call(Unknown Source)
	at grails.plugin.springsecurity.rest.RestTokenValidationFilter.processFilterChain(RestTokenValidationFilter.groovy:118)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
	at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:190)
	at grails.plugin.springsecurity.rest.RestTokenValidationFilter.doFilter(RestTokenValidationFilter.groovy:84)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at javax.servlet.FilterChain$doFilter.call(Unknown Source)
	at grails.plugin.springsecurity.rest.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.groovy:143)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.groovy:62)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at grails.plugin.springsecurity.web.SecurityRequestHolderFilter.doFilter(SecurityRequestHolderFilter.groovy:58)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)

@sarbogast
Copy link

OK, I really couldn't reproduce in a sample app. But I can confirm that your fix with lower priority marshallers does not fix this exception. I found the same exception report in old versions of Grails: http://grails.1312388.n4.nabble.com/Marshallers-are-blowing-up-in-2-3-5-anyone-else-td4653954.html

Once I comment out this whole section in RestBuilder's constructor, my tests pass again.

@jameskleeh
Copy link
Contributor

@sarbogast Without something to debug, I can't fix the issue. In the meantime I'll be adding an option to turn off the creation of the converters

@sarbogast
Copy link

I know, but for the life of me I couldn't isolate what is going on and why it's failing. Apparently in my case it fails to call getClass() on an object of a class I don't even know of. And impossible to figure out what was common to those 3 failing tests compared to the 117 others.

@jameskleeh
Copy link
Contributor

@benorama @sarbogast In the next version of GORM, you can do new RestBuilder(registerConverters: false) which will prevent the converters from being intialized

@benorama
Copy link
Author

That's great! Would it be possible to have a global config parameter, since you might not control instances created from plugins?

@abrahaj
Copy link

abrahaj commented Feb 15, 2019

@benorama @sarbogast In the next version of GORM, you can do new RestBuilder(registerConverters: false) which will prevent the converters from being intialized

Run into the same issue. Solved by applying the registerConverters:false (Grails 3.3.9)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants