Spring不使用带注释的构造函数(@JsonCreator)进行实例化

时间:2014-10-26 17:14:08

标签: java spring-mvc jackson

我正在使用Spring 4.1.1和JavaConfig以及Jackson 2.4.3。

我的控制器看起来像这样:

@RestController
public interface PatientWebService {

    @RequestMapping(value = "/patients", method = POST)
    PatientResource createPatient(@RequestBody PatientResource resource);
}

我发送的json看起来像这样:

{
    "firstName": "Max",
    "lastName": "Mustermann",
    "birthDate": "1964-04-14",
    "sex": "MAN"
}

我想将它解析为这个类:

package at.landsteiner.patient.web;

import at.landsteiner.patient.Patient;
import at.landsteiner.patient.Sex;
import at.landsteiner.web.EntityResource;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.LocalDate;

public class PatientResource extends EntityResource {

    private String firstName;
    private String lastName;
    private LocalDate birthDate;
    private Sex sex;

    @JsonCreator
    public PatientResource(@JsonProperty("firstName") String firstName, @JsonProperty("lastName") String lastName, @JsonProperty("birthDate") LocalDate birthDate, @JsonProperty("sex") Sex sex) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.birthDate = birthDate;
        this.sex = sex;
    }

    // getter
}

这是我得到的输出:

19:43:41,842 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.DispatcherServlet.doService - DispatcherServlet with name 'DispatcherServlet' processing POST request for [/questionnaire-api/patients]
19:43:41,846 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping.getHandlerInternal - Looking up handler method for path /patients
19:43:41,850 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping.getHandlerInternal - Returning handler method [public at.landsteiner.patient.web.PatientResource at.landsteiner.patient.web.PatientWebServiceImpl.createPatient(at.landsteiner.patient.web.PatientResource)]
19:43:41,850 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.b.f.s.DefaultListableBeanFactory.doGetBean - Returning cached instance of singleton bean 'patientWebServiceImpl'
19:43:41,868 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver.resolveException - Resolving exception from handler [public at.landsteiner.patient.web.PatientResource at.landsteiner.patient.web.PatientWebServiceImpl.createPatient(at.landsteiner.patient.web.PatientResource)]: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [at.landsteiner.patient.web.PatientResource]: No default constructor found; nested exception is java.lang.NoSuchMethodException: at.landsteiner.patient.web.PatientResource.<init>()
19:43:41,869 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver.resolveException - Resolving exception from handler [public at.landsteiner.patient.web.PatientResource at.landsteiner.patient.web.PatientWebServiceImpl.createPatient(at.landsteiner.patient.web.PatientResource)]: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [at.landsteiner.patient.web.PatientResource]: No default constructor found; nested exception is java.lang.NoSuchMethodException: at.landsteiner.patient.web.PatientResource.<init>()
19:43:41,870 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver.resolveException - Resolving exception from handler [public at.landsteiner.patient.web.PatientResource at.landsteiner.patient.web.PatientWebServiceImpl.createPatient(at.landsteiner.patient.web.PatientResource)]: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [at.landsteiner.patient.web.PatientResource]: No default constructor found; nested exception is java.lang.NoSuchMethodException: at.landsteiner.patient.web.PatientResource.<init>()
19:43:41,878 INFO  [stdout] (default task-1) 19:43:41 DEBUG o.s.w.s.DispatcherServlet.processRequest - Could not complete request
19:43:41,879 INFO  [stdout] (default task-1) org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [at.landsteiner.patient.web.PatientResource]: No default constructor found; nested exception is java.lang.NoSuchMethodException: at.landsteiner.patient.web.PatientResource.<init>()
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:107) ~[spring-beans-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:139) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:79) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:105) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar!/:1.0.0.Final]
19:43:41,879 INFO  [stdout] (default task-1)    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,879 INFO  [stdout] (default task-1)    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [jboss-servlet-api_3.1_spec-1.0.0.Final.jar!/:1.0.0.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78) [wildfly-undertow-8.1.0.Final.jar!/:8.1.0.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:56) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61) [wildfly-undertow-8.1.0.Final.jar!/:8.1.0.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,882 INFO  [stdout] (default task-1)    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:177) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:727) [undertow-core-1.0.15.Final.jar!/:1.0.15.Final]
19:43:41,883 INFO  [stdout] (default task-1)    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0]
19:43:41,883 INFO  [stdout] (default task-1)    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0]
19:43:41,883 INFO  [stdout] (default task-1)    at java.lang.Thread.run(Thread.java:744) [na:1.8.0]
19:43:41,884 INFO  [stdout] (default task-1) Caused by: java.lang.NoSuchMethodException: at.landsteiner.patient.web.PatientResource.<init>()
19:43:41,884 INFO  [stdout] (default task-1)    at java.lang.Class.getConstructor0(Class.java:2971) ~[na:1.8.0]
19:43:41,884 INFO  [stdout] (default task-1)    at java.lang.Class.getDeclaredConstructor(Class.java:2165) ~[na:1.8.0]
19:43:41,884 INFO  [stdout] (default task-1)    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:104) ~[spring-beans-4.1.1.RELEASE.jar:4.1.1.RELEASE]
19:43:41,884 INFO  [stdout] (default task-1)    ... 43 common frames omitted

如何配置Spring将实例化委托给Jackson?
是否可以将@JsonCreator@RequestBody的使用结合起来?

我的JavaConfig看起来像这样:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "at.landsteiner" })
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(converter());
    }

    @Bean
    public MappingJackson2HttpMessageConverter converter() {
        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(new JSR310Module());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        return new MappingJackson2HttpMessageConverter(mapper);
    }
}

2 个答案:

答案 0 :(得分:7)

虽然我没有使用Spring 4.1.1进行测试(但是使用Spring 4.0.5),但我发现问题是注释@RequestBody仅出现在界面中。

Spring不会从界面中查看方法参数的注释(甚至不确定是否可能),而只是来自具体实现。

由于在具体实现上缺少注释,Spring确实尝试使用Jackson来实例化对象,但使用常规bean方法。

如果你只是简单地添加注释具体方法的参数,一切都会正常工作

答案 1 :(得分:-1)

org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [at.landsteiner.patient.web.PatientResource]: No default constructor found; nested exception is java.lang.NoSuchMethodException: at.landsteiner.patient.web.PatientResource.<init>()
19:43:41,879 INFO  [stdout] (default task-

Spring尝试使用默认构造函数初始化bean而不使用参数但是构造函数获取对象。 你也写了一个界面,但我没有看到界面的实现