SpringBoot: call a query using RestTemplate

1.1k Views Asked by At

I've just started using Spring Boot and I want to use RestTemplate to call a query and return its result.

@Repository
public interface ApplicantRepository extends CrudRepository<Applicant, Integer> {

@Query("SELECT a FROM Applicant a WHERE a.propertyTypeId = :typeId" +
        " AND a.bedrooms = :bedrooms" +
        " AND a.budget = :price")
List<Applicant> findByMatchingCriteria(@Param("typeId")int typeId, @Param("bedrooms") int bedrooms,
                                      @Param("price") int price);
}

I'm calling the query "findByMatchingCriteria" in this RestController:

@RestController
public class MatchingController {

private RestTemplate restTemplate = new RestTemplate();

@RequestMapping(method = GET, value = "matchingByProperty/{propertyId}")
public List matchingByProperty(@PathVariable int propertyId) {
    Property property = restTemplate.getForObject("http://localhost:8080/api/properties/" + propertyId, Property.class);

    return restTemplate.getForObject("http://localhost:8080/api/applicants/search/findByMatchingCriteria?typeId=" + property.getTypeId()
                                            + "&bedrooms=" + property.getBedrooms()
                                            + "&price=" + property.getPrice(), List.class);
}
}

The Property looks like this:

@Entity
public class Property {
private @Id @GeneratedValue int id;
private String fullAddress;
private int typeId;
private int subtypeId;
private int bedrooms;
private int price;

private Property() {}

public Property(String fullAddress, int typeId, int subtypeId, int bedrooms, int price) {
    this.fullAddress = fullAddress;
    this.typeId = typeId;
    this.subtypeId = subtypeId;
    this.bedrooms = bedrooms;
    this.price = price;
}
// getters and setters
}

When I test the "matchingByProperty/{propertyId}" url I get the following error:

exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP     message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@3bd79387; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@3bd79387; line: 1, column: 1]

How can I call the query using RestTemplate? Or is there a better way to do it?

2

There are 2 best solutions below

0
On BEST ANSWER

Came up with a solution for my problem.

Created a REST method in the ApplicantController that calls the query of the ApplicantRepository:

@RequestMapping(method = POST, value = "/api/applicants/getMatchedApplicants")
public List getMatchedApplicants(@RequestBody HashMap property) {

    List<Applicant> applicants = applicantRepository.matchedApplicants((int) property.get("typeId"),
                                                                        (int) property.get("bedrooms"),
                                                                        (int) property.get("price"));

    return applicants == null ? new ArrayList() : applicants;
}

And then the MatchingController calls the method in the ApplicantController by REST.

That's what I wanted, two different services (the Matching and the Applicant) to communicate by REST.

Thank you @Adam your suggestion helped me.

1
On

If you just want to call your own repository from a controller, there is no need to go over HTTP with RestTemplate. Simply inject the repository into your controller, and call the method:

@RestController
public class MatchingController {

  @Autowired
  private ApplicantRepository applicantRepository;

  @RequestMapping(method = GET, value = "matchingByProperty/{propertyId}")
  public List matchingByProperty(@PathVariable int propertyId) {
    // You probably should not be going over HTTP for this either
    // and autowiring a property repository.
    Property property = restTemplate.
      getForObject("http://localhost:8080/api/properties/" + propertyId, Property.class);

    return applicantRepository.findByMatchingCriteria(property.getTypeId(), property.getBedrooms(), property.getPrice());
  }
}

If you do want to go over HTTP for some reason, you can use the methods found here: Get list of JSON objects with Spring RestTemplate