Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

null fields with Spring Boot REST controller and JSON

I have an Spring Boot application with this Gradle build file:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'spring-boot'
apply plugin: 'war'

sourceCompatibility = 1.7
targetCompatibility = 1.7

version = '1.0'

buildscript {
    ext {
        springBootVersion = '1.1.9.RELEASE'
    }
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.9.RELEASE")
    }
}

jar {
    manifest {
        attributes 'Implementation-Title': 'Server', 'Implementation-Version': version
    }
}

war {
    baseName = 'gs-convert-jar-to-war'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
    maven { url "http://repo.spring.io/libs-snapshot" }
    maven { url "http://maven.springframework.org/milestone" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")

    compile("org.springframework.boot:spring-boot-starter-tomcat:${springBootVersion}")

    compile("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-aop:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-data-jpa:${springBootVersion}")

    compile("org.springframework.data:spring-data-rest-webmvc")

    compile("org.hsqldb:hsqldb")

    compile("com.google.guava:guava:17.0")
    compile("org.apache.httpcomponents:httpclient:4.3.4")
    compile("commons-io:commons-io:2.4")

    testCompile("junit:junit")
}

With this application file:

@EnableAutoConfiguration
@Configuration
@ComponentScan
@Import({ BasicSecurityConfiguration.class, HTTPSTomcatConfiguration.class,
        MultiPartConfiguration.class })
public class Application extends RepositoryRestMvcConfiguration {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    // use JSON
    @Override
    public ObjectMapper halObjectMapper() {
        return new ResourcesMapper();
    }

}

this configuration files:

@Configuration
@EnableWebSecurity
public class BasicSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // no cache
        http.requestCache().requestCache(new NullRequestCache());

        // use HTTPS
        http.requiresChannel().anyRequest().requiresSecure();
        http.portMapper().http(8080).mapsTo(8443);

        // this replaces the web security http configuration
        http.authorizeRequests().antMatchers("/**").authenticated().and()
                .httpBasic();

        // disable CSRF
        http.csrf().disable();
    }

    @Autowired
    protected void registerAuthentication(
            final AuthenticationManagerBuilder auth) throws Exception {

        // FIXME create a full user registry
        // in-memory users
        auth.inMemoryAuthentication().withUser("admin").password("pass")
                .authorities("admin", "user").and().withUser("user")
                .password("pass").authorities("user");
    }

}
@Configuration
public class HTTPSTomcatConfiguration {
    @Bean
    EmbeddedServletContainerCustomizer containerCustomizer(
            @Value("8443") final int port,
            @Value("keystore.p12") Resource keystoreFile,
            @Value("tomcat") final String alias,
            @Value("localhost") final String keystorePass,
            @Value("PKCS12") final String keystoreType) throws Exception {

        final String absoluteKeystoreFile = keystoreFile.getFile()
                .getAbsolutePath();

        return new EmbeddedServletContainerCustomizer() {
            public void customize(ConfigurableEmbeddedServletContainer container) {
                TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
                tomcat.addConnectorCustomizers(new TomcatConnectorCustomizer() {
                    public void customize(Connector connector) {
                        connector.setPort(port);
                        connector.setSecure(true);
                        connector.setScheme("https");
                        Http11NioProtocol proto = (Http11NioProtocol) connector
                                .getProtocolHandler();
                        proto.setSSLEnabled(true);
                        proto.setKeystoreFile(absoluteKeystoreFile);
                        proto.setKeyAlias(alias);
                        proto.setKeystorePass(keystorePass);
                        proto.setKeystoreType(keystoreType);
                    }
                });
            }
        };
    }
}
@Configuration
@EnableConfigurationProperties(MultipartProperties.class)
public class MultiPartConfiguration {

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        return new MultipartConfigElement("");
    }

}

this controller interface:

public interface Controller {

    @RequestMapping(value = "/t", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Test t(@RequestBody Test test);

}

and this controller implementation:

@RestController
public class ControllerImpl implements Controller {

    @Override
    public Test t(Test test) {
        return test;
    }
}

Everything seems to work fine, except the JSON serialization from client to server. When I execute this curl command:

curl --insecure -H "Authorization: Basic YWRtaW46cGFzcw==" -H "Content-Type: application/json" -X POST -d '{"a":"a","b":"b"}' https://localhost:8443/t

I get:

{"a":null,"b":null}

If I debug just in the controller implementation I see the fields as null. If I modify the controller like this:

@Override
public Test t(Test test) {
    Test t = new Test();
    t.setA("a");
    t.setB("b");
    return t;
}

I get the correct answer:

{"a":"a","b":"b"}

Why my app is not deserializing Test object properly?

like image 813
logoff Avatar asked Dec 01 '14 00:12

logoff


1 Answers

You have @RequestBody annotation in your interface you need to have it on the method implementation:

@RestController 
public class ControllerImpl implements Controller {

    @Override
    public Test t(@RequestBody Test test) {
        return test;
    }
}
like image 165
Ilya Ovesnov Avatar answered Sep 24 '22 20:09

Ilya Ovesnov