Skip to content

BeanConstraintsDescriptor gives ClassCastException with nested generic types #55

@arjanvlek

Description

@arjanvlek

For one of our projects, I had the following structure inside one of the persistable entities:

@Transient
private final Map<UUID, List<String>> entityIdsWithSomething = new ConcurrentHashMap<>(); // Only for CSV import of XXX

When accessing the /constraints endpoint, which is provided by BeanConstraintController, the following error is thrown:

10-09-2020 11:14:21.282 ERROR [080-exec-1] l._42.xxx.config.web.errorhandling.ControllerExceptionAdvice:122 Handling request, for [nl._42.jarb.constraint.metadata.BeanConstraintController#describeAll()], resulted in the following exception.
java.lang.ClassCastException: class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to class java.lang.Class (sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl and java.lang.Class are in module java.base of loader 'bootstrap')
	at nl._42.jarb.constraint.metadata.BeanConstraintDescriptor.describeBean(BeanConstraintDescriptor.java:85)
	at nl._42.jarb.constraint.metadata.BeanConstraintService.describe(BeanConstraintService.java:56)
	at nl._42.jarb.constraint.metadata.BeanConstraintService.describeAll(BeanConstraintService.java:30)
	at nl._42.jarb.constraint.metadata.BeanConstraintController.describeAll(BeanConstraintController.java:25)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)

This seems to be caused by

Class<?> valueType = (Class<?>) getGenericTypes(field)[1];

Which assumes that parameterizedType.getActualTypeArguments() always returns a Class, but this is not the case if another generic type is present (in this case: List<String>).

See https://stackoverflow.com/questions/24829146/classcastexceptionjava-lang-class-cannot-be-cast-to-java-lang-reflect-parameter in which this is explained.

Something should be changed in the BeanConstraintsDescriptor to handle cases like this (or as a quick fix: if the field is annotated with @Transient, then simply skip processing it)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions