Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to post new entity with relationship using RestTemplate and Spring Data REST

I'm struggling on how to use Spring's RestTemplate with the hateoas module to create new related entities. I've tried fetching a Foo object and assigning it to the Bar object I'm trying to create. When I post that the server gives me a Http 400 Bad Request. When I tried to post a Resource object with a link, I get this exception:

 Exception in thread "main" org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.hateoas.Resource]

I'm at a loss for figuring out how to create the correct POST request using RestTemplate against a Spring Data REST service.

Background: I have two classes Foo and Bar. Foo has a OneToMany relationship with Bar and thus Bar has a ManyToOne relationship with Foo.

The code for each class is as follows:

Foo:

package com.foo;

//Imports omitted for clarity

@Entity
@Getter
@Setter
@Table(name="Foo", schema="dbo")
public class Foo implements Identifiable<Integer> {

    @Id
    @Column(name="FOO_I")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name="Name")
    private String name;

    @Column(name="descript")
    private String description;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="foo")  
    private Set<Bar> bars;
}

Bar:

package com.foo;

@Entity
@Getter
@Setter
@Table(name="Bar", schema="dbo")
public class Bar implements Identifiable<Integer> {

    @Id
    @Column(name="BAR_I")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name="barname")
    private String name;

    @Column(name="bardescription")
    private String description;

    @Column(name="qty")
    private int qty;

    @ManyToOne
    @JoinColumn(name="FOO_I", referencedColumnName="FOO_I", nullable=false) 
    private Foo foo;
}

I'm attempting to post to http://nonexistantdomain.com.mx.uk.ch:8080/bars to create a new bar that is related to a foo whose FOO_I is 1.

I can see output from things like http://nonexistantdomain.com.mx.uk.ch:8080/foos/1 and http://nonexistantdomain.com.mx.uk.ch:8080/foos/1/bars and http://nonexistantdomain.com.mx.uk.ch:8080/bars/5. So I know the relationships are working.

Further I'm able to create a new bar using wget and the following post body to http://nonexistantdomain.com.mx.uk.ch:8080/bars/:

{
  "name": "newWgetBar",
  "description": "just another bar",
  "qty": 2,
  "foo" : "http://nonexistantdomain.com.mx.uk.ch:8080/foos/1"
}

Which works successfully. How can I use Spring's RestTemplate to do this so I can accomplish what I need from my java code?

Edit:

Here are the examples I have tried.

private RestTemplate acquireTemplate(boolean isHalJson) {
    ObjectMapper mapper = new ObjectMapper();                       
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.registerModule(new Jackson2HalModule());
    mapper.registerModule(new JodaModule());        

    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
    converter.setObjectMapper(mapper);

    return new RestTemplate(Collections.<HttpMessageConverter<?>> singletonList(converter));
}

public void addABar(String name) {
    Bar b = new Bar();
    b.setName(name);
    b.setDescription("An added bar.");
    b.setQty(2);
    RestTemplate template = acquireTemplate();
    ResponseEntity<Foo> f = template.getForEntity("http://localhost:8080/foos/1", Foo.class);
    Link l = new Link("foo","http://localhost:8080/foos/1");
    Resource<Bar> r = new Resource<Bar>(b,l);       
    URI i = template.postForLocation("http://localhost:8080/bars", r);
}

public void addABarAttempt2(String name) {
    Bar b = new Bar();
    b.setName(name);
    b.setDescription("An added bar.");
    b.setQty(2);
    RestTemplate template = acquireTemplate();
    ResponseEntity<Foo> f = template.getForEntity("http://localhost:8080/foos/1", Foo.class);
    b.setFoo(f.getBody());
    URI i = template.postForLocation("http://localhost:8080/bars", b);
}

public void addABarAttempt3(String name) {
    Bar b = new Bar();
    b.setName(name);
    b.setDescription("An added bar.");
    b.setQty(2);
    RestTemplate template = acquireTemplate();
    template.put("http://localhost:8080/foos/1/bars",b);
}

All three examples fail for differing reasons.

like image 549
Peter Smith Avatar asked Nov 01 '22 13:11

Peter Smith


1 Answers

What about use this code:

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

        String uri = new String("url");

        Bar b= new Bar();
        bar.setName("newWgetBar");

        rt.postForObject(uri, b, Bar.class);

it would be usefull if you show us what do you program so far on your RestTemplate

like image 164
paul Avatar answered Nov 15 '22 03:11

paul