简体   繁体   中英

Spring @RequestBody without using a pojo?

I am using Spring Boot and I have a method defined like this in my controller

@PostMapping("/update)
public void update(@RequestBody User user) {
    ...
}

However in my post request from client(frontend or postman for example), I have something like this:

{
    "firstName" : "John",
    "lastName" : "Doe",
    "id" : 1234,
    "metaInfoId" : "5457sdg26sg4636"
}

The thing is my User pojo has only firstName , id and lastName instance fields in it.However in my request I have to send metaInfoId as well for some other needs. So how can I retrieve or separate metaInfoId and User model in my controller method above?

Do I have to create another model class called UserModelRequest and add all User fields along with metaInfoId field and then use @RequestBody ? Is there a way to simply remove metaInfoId from the request and then take everything else and dump it into User pojo? You could do this easily in nodejs for example(just splice your object and take what you need).

So is there a way to do it in java spring without having to create another model class?

You can annotate your POJO with @JsonIgnoreProperties(ignoreUnknown = true) so the fields that it does not contain are ignored. Ex

@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private int id;
    private String firstName;
    private String lastName;

    ... getters & setters ...
}

Additionally, you should not include metadata in the body of your rest request. The correct place for this information would be in a headers. This would change your method signature to:

@PostMapping("/update)
public void update(@RequestBody User user, @RequestHeader(value="metaInfoId") String metaInfoId) {
    ...
}

If you must add the information in the request, then your would need to update the User pojo class to include this field (Or have it extend a class with the metaInfoId field)

Lastly, you really don't want to create a new type. You can change the signature to accept a map and retrieve the necessary info like:

@PostMapping("/update)
public void update(@RequestBody Map<String, Object> userMap) {
    String metaInfoId = userMap.get("metaInfoId");

    ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
    final User user = mapper.convertValue(userMap, User.class);
}

I understand from the question that you may need two cases:

  • Send a property in the JSON that does not have a corresponding field in the User object. In that case, you need to still use the User object with the supplied fields and ignoring the rest that was provided in the JSON
  • Send additional properties in the JSON and you still need to capture them in the User object without defining those extra properties specifically in the object.

I think in both cases, it is better to use Jackson than Gson as it has richer marshaling controls over the objects. Thus, my below solution assumes that you will use Jackson with Spring web - the maven dependency for Jackson is as follows:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
</dependency>

First Case

In this case, you need Jackson to ignore the metaInfoId property when it deserializes the JSON to the User object. To achieve this, please add this annotation to the top of your User class.

@JsonIgnoreProperties(ignoreUnknown = true)
class User {
    private String firstName;
    private String lastName;

    // the rest of the class definition
}

Second Case

In the second case, you still need to capture the extra properties. I'd suggest adding a catch all HashMap that accepts the extra undefined properties and you can access it by key/value. To achieve this, you'll need to add the following to your User class, or better to create an abstract class that has this code where User extends it.

class User {
    private String firstName;
    private String lastName;
    private Map<String, Object> extra;

    @JsonAnySetter
    public void addExtra(final String key, final Object value){
        this.extra.put(key, value);  
    }

    @JsonAnyGetter
    public Map<String, Object> getExtra() {
        return Collections.unmodifiableMap(this.extra);
    }

    // the rest of the class definition
}

Hope this helps

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