简体   繁体   中英

Spring 5 MVC JSON ser/deser not respecting properties (but works for XML)

I'm having a bizarre situation on a new setup using vanilla Spring Boot 2/Spring 5/Java 10/Jigsaw where no matter what I do, pulling an object through Spring MVC gives me an empty {} JSON object instead of my object properties.

BUT ... if I use an Accept header of application/xml instead of application/json, I get all the right properties. Maybe I'm losing my mind but I seem to recall in previous versions that if it worked on one side (xml), it should work on the other (json) and vice/versa.

I've traced it down internally to the BeanSerializer being created for my model class, with no properties. I'm just not sure why this is. I've traced through the execution to see Jackson is running during the http convert process ... it's just ignoring all properties inside the object.

Here's my setup:

Maven:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.4.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>10</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.2.4</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-integration</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>javax.activation-api</artifactId>
        <version>1.2.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-jaxb-annotations</artifactId>
        <version>2.9.6</version>
        <scope>runtime</scope>
    </dependency>

module-info:

module stupid.example {
opens com.example.microservice.datasynchronizer;
opens com.example.microservice.datasynchronizer.model;
opens com.example.microservice.datasynchronizer.webflux to spring.beans, spring.core, spring.web ;
opens com.example.microservice.datasynchronizer.dao to spring.core ;

requires java.base ;
requires java.xml.bind ;
requires spring.boot;
requires spring.boot.autoconfigure;
requires spring.beans ;
requires spring.context ;
requires spring.core ;
requires spring.data.commons ;
requires spring.web ;
requires spring.webmvc ;
requires java.persistence ;
requires org.junit.jupiter.api;
requires spring.test;
requires spring.boot.test ;
}

Model class (latest, with jaxb annotations just in case):

@Entity
@XmlRootElement
public class Thingamajig {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@XmlElement
private Long id;
@XmlElement
private String firstName;
@XmlElement
private String lastName;

public Thingamajig ( ) { ; }

public Thingamajig(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

@Override
public String toString() {
    return String.format("Thingamajig [id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
}
}

Controller:

@RestController
public class ThingamajigController {

@Autowired
private ThingamajigDao _dao ;

@GetMapping("/thing/{id}")
public Thingamajig getPerson(@PathVariable Long id) {
    Optional<Thingamajig> found = _dao.findById(id) ;
    return found.get() ;
}

@PostMapping ( "/thing" )
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Thingamajig person) {
    _dao.save(person) ;
}
}

Configuration:

@EnableWebMvc
@SpringBootApplication
public class DataSynchronizerApplication {

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

What the heck am I missing? Any help appreciated.

You simply forgot to define getters and setters in your Thingamajig class.

XML works because you have defined the annotations on the attributes but JSON serializer is looking for getters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM