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!