Home > Net >  Why does Spring-content produce an IllegalStateException on startup if an Entity has a field which i
Why does Spring-content produce an IllegalStateException on startup if an Entity has a field which i

Time:04-07

We are using Spring-content as a file storage solution in a web application, and are upgrading the version from 1.0.0.M10 to 2.1.0. Suddenly our microservice refuses to start up because it cannot load its ApplicationContext, and I cannot for the life of me understand why. The Spring-content changelog mentioned breaking changes involving annotations decorating the ContentStore itself --which we don't have-- but nothing I read mentioned annotations on the entity class. Am I doing something wrong, or is this a bug of some kind?

I've made a simplified example that produces the same type of exception because I'm not sure if I'm allowed to share the original source code.

My Spring-content dependencies. The only other dependencies are for lombok, postgres, and hibernate on an otherwise new project:

        <dependency>
            <groupId>com.github.paulcwarren</groupId>
            <artifactId>spring-content-fs-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.paulcwarren</groupId>
            <artifactId>spring-content-rest-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

My Entity:

@Data
@Table(name = "employee")
public class EmployeeEntity  {

    @Id
    @Column(name = "id")
    private UUID employeeId;
    
    @ContentId
    @Column(name = "content_id")
    private UUID contentId;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "employee_type")
    private EmployeeType employeeType;

}

The enum:

public enum EmployeeType {
    ASSOCIATE,
    MANAGER,
    DIRECTOR,
    EXECUTIVE;
}

My repo:

public interface IEmployeeRepository extends JpaRepository<EmployeeEntity, UUID> {

}

And my ContentStore:

public interface IEmployeeContentStore extends ContentStore<EmployeeEntity, String> {

}

When I either try to run the application or run a JUnit test that loads the context, I get a console full of these errors, which seems to fill the buffer as far back as I can scroll.

    at org.springframework.content.commons.mappingcontext.ContentPropertyBuilderVisitor.visitField(ContentPropertyBuilderVisitor.java:143) ~[spring-content-commons-2.1.0.jar:na]
    at org.springframework.content.commons.mappingcontext.ClassWalker.accept(ClassWalker.java:24) ~[spring-content-commons-2.1.0.jar:na]

By capturing the console output to a text file, it seems this is the root exception:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.content.commons.mappingcontext.MappingContext]: Factory method 'mappingContext' threw exception; nested exception is java.lang.StackOverflowError
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.18.jar:5.3.18]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.18.jar:5.3.18]
    ... 134 common frames omitted
Caused by: java.lang.StackOverflowError: null
    at java.base/java.lang.reflect.Field.copy(Field.java:153) ~[na:na]
    at java.base/java.lang.reflect.ReflectAccess.copyField(ReflectAccess.java:151) ~[na:na]
    at java.base/jdk.internal.reflect.ReflectionFactory.copyField(ReflectionFactory.java:381) ~[na:na]
    at java.base/java.lang.Class.copyFields(Class.java:3383) ~[na:na]
    at java.base/java.lang.Class.getDeclaredFields(Class.java:2249) ~[na:na]
    at org.springframework.content.commons.mappingcontext.ContentPropertyBuilderVisitor.visitClass(ContentPropertyBuilderVisitor.java:48) ~[spring-content-commons-2.1.0.jar:na]
    at org.springframework.content.commons.mappingcontext.ClassWalker.accept(ClassWalker.java:17) ~[spring-content-commons-2.1.0.jar:na]

I've traced the problem to what seems to be the @Enumerated annotation on the entity class. Removing this field entirely prevents the exception from occurring.

The nearest explanation I could find is that a StackOverflowException is something you'd expect if you had classes calling each other recursively: Spring Boot StackOverFlowError : Null However this is at least not directly applicable as I don't have any mapping between entities such as in the example.

Things I have tried:

  • Removing @Data to see if lombok's toString() was indeed the culprit. (See above)
  • Using a converter class instead of @Enumerated

The only solution that seemed to work was changing EmployeeType to a String, in which case everything loads correctly. It would be less than ideal if this were the only solution, as the entire microservice would have to be refactored to use a String instead of an Enum for that field.

Can anyone point me in the right direction making an enumerated field work in an entity used in a ContentStore in this way? Thank you so much!


Edit: Added postgres and hibernate dependencies, which I overlooked initially

CodePudding user response:

Arnaud's link pointed to the correct solution. The service will now start up as expected when the spring-content dependency was updated to 2.2.0-SNAPSHOT:

        <dependency>
            <groupId>com.github.paulcwarren</groupId>
            <artifactId>spring-content-fs-boot-starter</artifactId>
            <version>2.2.0-SNAPSHOT</version>
        </dependency>

Thanks again!

  • Related