0

I'm trying to get an XML response from my server but for some reason it still returns JSON. Maybe I'm misunderstanding what setAccept and setContentType are? At the moment I'm thinking that the get request is in XML but the client is only accepting / expecting json?

I've tried setting headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); to XML instead but it ends up giving me an error "Cannot find representation". I also took out JSON from the consumes = "" but it stopped working when i did that too.

RestClient.java

public class RestClient {

     public static void getJsonEmployee(String id) throws JSONException, IOException {

          String uri = "http://localhost:8080/employees/" + id;

             RestTemplate restTemplate = new RestTemplate();

             HttpHeaders headers = new HttpHeaders();
             headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
             headers.setContentType((MediaType.APPLICATION_XML));
             HttpEntity entity = new HttpEntity(headers);


            ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
             String result = response.getBody();
             System.out.println(result);

         }




public static void postJsonEmployee(String id, String name, String description) {

    final String uri = "http://localhost:8080/employees/";


    Employee newemp = new Employee(id, name, description);


    RestTemplate restTemplate = new RestTemplate();


    HttpHeaders httpHeaders = restTemplate.headForHeaders(uri);


    httpHeaders.setContentType(MediaType.APPLICATION_JSON);


    Employee result = restTemplate.postForObject( uri, newemp, Employee.class);


    httpHeaders.setContentType(MediaType.APPLICATION_JSON);


     }

    public static void main(String[] args) throws IOException, JSONException {

     System.out.println("GET or POST?");
     BufferedReader getpost = new BufferedReader(new InputStreamReader(System.in));
     String selection = getpost.readLine();

     switch(selection) {

     case "GET":

     System.out.println("Type in the employee's ID");
     BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
     String employeeid = reader.readLine();
     getJsonEmployee(employeeid);
     break;

     case "POST":

         System.out.println("Type in the employee's ID");
         Scanner scan = new Scanner(System.in);
         String newid = scan.nextLine();
         System.out.println("Type in the employee's name");
         String newname = scan.nextLine();
         System.out.println("Type in the employee's description");
         String newdesc = scan.nextLine();
         postJsonEmployee(newid, newname, newdesc);
         break;
     }

}
}

EmployeeController.java

@RestController
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @RequestMapping(path = "/employees", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_PLAIN_VALUE})
    public @ResponseBody HashMap<String, Employee> retrieveEmployees() {
        return employeeService.retrieveAllEmployees();
    }

    @RequestMapping(path = "/employees/{employeeId}",produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_PLAIN_VALUE})
    public @ResponseBody Employee retrievebyId(@PathVariable String employeeId) {
        return employeeService.retrieveEmployee(employeeId);
    }

    @PostMapping(path="/employees", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
    public ResponseEntity<Void> registeremployee(@RequestBody Employee newemployee) {

        Employee employee = employeeService.addEmployee(newemployee.getId(),newemployee.getName(), newemployee.getDescription());

        if (employee == null)
            return ResponseEntity.noContent().build();

        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path(
                "/{id}").buildAndExpand(employee.getId()).toUri();

        return ResponseEntity.created(location).build();
    }

}

EmployeeService.java

@Component
public class EmployeeService implements Serializable {


    static HashMap<String, Employee> employees = new HashMap<>();

    static {
        //Initialize Data

        Team team1 = new Team("t1", "Java team", "Java Dev Team");

        Employee Joe = new Employee("employee1", "Joe Smith","Human Resources");

        Employee Bob = new Employee("employee2", "Bob Jones",
                "Developer");

        employees.put("employee1", Joe);
        employees.put("employee2", Bob);
    }

    public HashMap<String, Employee> retrieveAllEmployees() {
        return employees;
    }

    public Employee retrieveEmployee(String employeeId) {
        return employees.get(employeeId);
    }
    //private SecureRandom random = new SecureRandom();

    public Employee addEmployee(String id, String name, String description) {

        //String randomId = new BigInteger(130, random).toString(32);
        Employee employee = new Employee(id, name, description);

        employees.put(id, employee);

        return employee;



    }

    public HashMap<String, Employee> getEmployees(){
        return employees;
    }

    public void setEmployees(HashMap<String, Employee> employees) {
        this.employees = employees;
    }


}

Employee.java

@XmlRootElement
public class Employee implements Serializable {

  private String id;

  private String name;

  private String description;
  // private List<Team> teams;

  public Employee() {

  }

  public Employee(String id, String name, String description) {
    this.id = id;
    this.name = name;
    this.description = description;
    // this.teams = teams;

  }

  @XmlAttribute
  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  @XmlElement
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @XmlElement
  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  @Override
  public String toString() {
    return String.format("employee [id=%s, name=%s, description=%s]", id, name, description);
  }

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot</groupId>
    <artifactId>employee-model</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>employee-model</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>



    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.2</version>
        </dependency>

            <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>
        <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>



</project>

Log

13:13:09.818 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/employees/
13:13:09.831 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
13:13:09.857 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
13:13:09.859 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.lang.String] as "application/json;charset=UTF-8"
{"employee1":{"id":"employee1","name":"Joe Smith","description":"Human Resources"},"employee2":{"id":"employee2","name":"Bob Jones","description":"Developer"}}
cccc
  • 65
  • 1
  • 7
  • 1
    Do you understand what the `Accept` and `Content-Type` headers do? – chrylis -cautiouslyoptimistic- Aug 09 '19 at 17:36
  • This isn't the cause of your problem (which is why this isn't an answer) but you don't need `@ResponseBody` when you're using `@RestController`. – Paul Aug 09 '19 at 17:39
  • @chrylis From what I understand, the Accept header says what media type the client can accept. The content type header is saying what content it is sending – cccc Aug 09 '19 at 17:43
  • 1
    Please include your POM or Gradle build file. (As a side note, you are using a lot of the "hidden dependency" features that look cool but are generally agreed to have been a mistake; instead, inject your `EmployeeService` via constructor, and add an `MvcUriComponentsBuilder` as a method parameter.) – chrylis -cautiouslyoptimistic- Aug 09 '19 at 18:15
  • @chrylis I added the pom build file – cccc Aug 09 '19 at 18:41

2 Answers2

1

I found out that the issue was that I was missing the jackson xml dependency. Add this to the pom.xml

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>
cccc
  • 65
  • 1
  • 7
0

Is there any particular reason why you are using MediaType.APPLICATION_XML_VALUE instead of MediaType.APPLICATION_XML

I would rather change my REST endpoint to something like this

 @RequestMapping(path = "/employees/{employeeId}",produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}, consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
    public Employee retrievebyId(@PathVariable String employeeId) {
        return employeeService.retrieveEmployee(employeeId);
    }

halfer
  • 19,824
  • 17
  • 99
  • 186
MRTJ
  • 141
  • 7
  • When I use APPLICATION_XML for produces = "", it says Type mismatch: cannot convert from MediaType to String[] – cccc Aug 09 '19 at 18:36
  • With your original code can you check whether your Employee class has proper getters and setters. Please see the link below. https://stackoverflow.com/questions/28466207/could-not-find-acceptable-representation-using-spring-boot-starter-web – MRTJ Aug 09 '19 at 19:07
  • I have employee.java above, I don't think I am missing any getters or setters – cccc Aug 09 '19 at 19:16
  • Could you please post the error stack trace from the client also when you are setting accept header as XML? – MRTJ Aug 09 '19 at 20:10