ystan-
ystan-

Reputation: 1536

Spring @RequestBody does not look up object

I'm writing a REST service using Spring-MVC/Hibernate and it seems @RequestBody is the recommended way to accept a bunch of parameters and map it into a POJO. However, it seems that the ID sent via POST gets translated into null instead of the actual object. Some sample code will explain better.

The service is straightforward:

@ResponseBody
@RequestMapping(value="add", method = RequestMethod.POST)
public ServiceResponse addTx(@RequestBody Transaction tx) {
    ...
    return ServiceResponse;
}

The Transaction entity has an Account entity:

@Entity
@Table(name="Transaction")
public class Transaction {
    @Column(name="code")
    private String code;
    @OneToOne
    @JoinColumn(name="accountId")
    private Account account;
    @Column(name="amount")
    private int amount;
    ...
}

The POST request payload from my browser reads:

{code: "ascasc", amount: 23, accountId: 1, ... }

But at the server-side, the constructed Transaction object has an Account value of null. i.e. that accountId of 1 does not get translated into the Account object. Am I missing something?

Upvotes: 3

Views: 3644

Answers (2)

Bohuslav Burghardt
Bohuslav Burghardt

Reputation: 34766

The behavior you describe is correct. When you use @RequestBody, it knows nothing about your persistence layer, it just maps the body of the request to the target object.

So when you post JSON containing accountId, Spring will try to find accountId property of the target object, but it doesn't exist (target object has only account property), so accountId will not be mapped. If you want the accountId to be correctly mapped, you must POST JSON like {..., account: { id: 1 }, ...}.


On a side note, it is a fairly common pattern to use transport objects for request/response object of web services and then map those to entity objects. You could then have accountId property in your transport object and then use that value when assembling the entity. One reason for this might be for example that you don't want to return certain model attributes from your webservices and you don't want to pollute your model layer with @JsonIgnore annotations for instance. This approach would also let you change your entity classes (e.g. rename some properties) without necessarily breaking your API. However this will add an extra layer of complexity, so you must decide whether it's worth it.

Upvotes: 5

Damien
Damien

Reputation: 4121

You could also use the annotation @JsonProperty - if you are using jackson

@OneToOne
@JoinColumn(name="accountId")
@JsonProperty("account")
private Account account;

This will map the json property account to your account variable

Upvotes: 2

Related Questions