6

I have a Spring Boot Project with Jackson.

Whenever I start it, I get this exception (production environment only).

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/apps/upiswitchv2/lib/upiswitchv2.jar!/BOOT-INF/lib/log4j-slf4j-impl-2.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/apps/upiswitchv2/lib/upiswitchv2.jar!/BOOT-INF/lib/slf4j-nop-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/apps/upiswitchv2/lib/upiswitchv2.jar!/BOOT-INF/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
2018-06-20 19:53:06,102 Log4j2-TF-1-AsyncLogger[AsyncContext@773cbf4f]-1 ERROR com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.lang.reflect.Parameter["declaringExecutable"]->java.lang.reflect.Method["parameters"]->java.lang.reflect.Parameter["declaringExecutable"]->java.lang.reflect.Method["parameters"]->java.lang.reflect.Parameter["declaringExecutable"]-

java.lang.reflect.Method["parameters"]->java.lang.reflect.Parameter["declaringExecutable"]->java.lang.reflect.Method["parameters"]->java.lang.reflect.Parameter["declaringExecutable"]->java.lang.reflect.Method["parameters"]->java.lang.reflect.Parameter["declaringExecutable"]->java.lang.reflect.Method["parameters"])

at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:706)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serializeContents(ObjectArraySerializer.java:256)
at com.fa.....................

Caused by: java.lang.StackOverflowError
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:709)
    ... 1011 more

Configuration

    <spring.boot.version>1.5.7.RELEASE</spring.boot.version>
    <jackson.version>2.8.5</jackson.version>

I have also provided a customMessageConverter

@Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter jsonConverter =
        new MappingJackson2HttpMessageConverter();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setSerializationInclusion(Include.NON_NULL);
    jsonConverter.setObjectMapper(objectMapper);
    return jsonConverter;
}

I also added Log4J Disruptor Jar and added property:

System.setProperty("log4j2.contextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");

Another observation: StackOverflowErrors increase whenever I get MethodArgumentNotValidException

For Example if I am using @Pattern Annotation, and if validation fails, @RestControllerAdvice catches MethodArgumentNotValidException, and in a short period of time (100ms) I get a StackOverflowError in SYSOUT.

James Z
  • 12,209
  • 10
  • 24
  • 44
Dipanshu Verma
  • 459
  • 3
  • 8
  • 22

1 Answers1

10

Looks like you are serializing a class with properties of parameters and declaringExecutable. And in this case parameters contains a reference to declaringExecutable and in turn declaringExecutable has a reference back to parameters. This results in an infinite loop as the class gets serialized to JSON.

Take a look at removing the reference in one spot or the other. Or mark one side of the chain as a @JsonIgnore

Based on the comment:

The java.lang.reflect is just for the code that is trying to do the serialization. If you don't have anything with declaringExecutable and parameters there must be some of your code that is attempting to serialize a library class with those properties. Take a look at the return types on your endpoints and see if you're returning anything from a library that has that circular dependency.

Or post your controller class and any other serialization specific code in the question.

Joe W
  • 2,773
  • 15
  • 35
  • But those are java classes, not classes of my package – Dipanshu Verma Jun 21 '18 at 04:55
  • Updated notes in the answer – Joe W Jun 21 '18 at 06:26
  • Can you please explain a bit more :- how to "see if you're returning anything from a library that has that circular dependency." Also, the exception comes up at server startup while loading a class, how do i narrow down suspects. Can I turn on some logs which might help me in debugging this issue. – Dipanshu Verma Jun 21 '18 at 07:56
  • Might be tough to solve with logging given that it occurs at startup but i would for sure add log calls to any of the controller methods where you expect the end result to be JSON. Also check anything you're serializing to JSON as part of your startup process. Post your Controller class here for more details – Joe W Jun 21 '18 at 11:57
  • I have a few things to share, will also soon share detailed version in the question after verifying: 1) There is a custom converter in code which consumes form/url-encoded requests and automatically converts them to JSON. 2) There is only 1 Api which consumes = "application/json" (rest all are consumes="application/x-www-form-urlencoded"), and it is the one which when fails in validation , sometimes I see a stackOverflow error 3) Point 2 is just a theory, which can be wrong, need to verify it , which I will be doing soon and posting results here – Dipanshu Verma Jun 22 '18 at 16:16
  • Could be looking for produces more than consumes though it could be either depending on the startup flow. Sounds like you may have found the API. What kind of args does the consumes ="application/json" take? – Joe W Jun 23 '18 at 21:22
  • No luck, All theories failed. And the error stopped coming, still trying to figure out what happened. – Dipanshu Verma Jun 28 '18 at 19:09
  • JsonIgnore worked for me. Got a similar stack overflow exception because I returned an EntityObject where and EntityObject refers to the first one. – Markus G. Nov 13 '18 at 14:28