12

I'm creating a simple rest controller with Spring Boot and the Web dependency. I'm trying to deserialize a JSON body to a test POJO with only 3 fields, but when I attempt to make a POST request, the server responds with a 500 error and the error I get in the console is:

.w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class java.util.LinkedHashMap

All of the code I have written is as follows:

EmailApplication.java:

package com.test.email.app;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = { "com.test.email" })
public class EmailApplication {

    public static void main(String[] args) {
        SpringApplication.run(EmailApplication.class, args);
    }

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {
            System.out.println("----- You're up and running with test-email-app! -----");
        };
    }
}

EmailController.java:

package com.test.email.controller;

import com.test.email.entity.TestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

import java.net.URI;

@RestController
public class EmailController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index() {
        TestEntity entity = new TestEntity();
        return "test-email-app index";
    }

    @RequestMapping(value = "/poster", method = RequestMethod.POST)
    public ResponseEntity<String> poster(@RequestBody TestEntity testEntity) {
        URI location = URI.create("/poster");
        return ResponseEntity.created(location).body(testEntity.getUrl());
    }
}

TestEntity.java

package com.test.email.entity;

/**
 * An entity for serialization/deserialization testing
 */
public class TestEntity {
    public String url;
    public int count;
    public double height;

    public TestEntity() {}

    public TestEntity(String url, int count, double height) {
        this.url = url;
        this.count = count;
        this.height = height;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }
}

I'm making a POST request with Postman using only the header Content-Type: application/json and with the body:

{ "url": "http://google.com", "count": 3, "height": 2.4 }

I don't know why Spring can't convert from a LinkedHashMap to my POJO. Any help would be appreciated.

Edit:

My pom.xml is as follows:

<?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>

    <groupId>com.test.email</groupId>
    <artifactId>test-email-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>test-email-app</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

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


</project>
mac
  • 123
  • 1
  • 6
  • 5
    When asking about an exception, always post the exact and complete stack trace of the exception. – JB Nizet Jul 18 '18 at 21:53
  • 2
    I don't see your code returning `LinkedHashMap` anywhere, so why does the error message say *"return value of type: `class java.util.LinkedHashMap`"*? I think you're confused about which methods it's complaining about. – Andreas Jul 18 '18 at 21:56
  • 1
    Not related with your request but your Getters/Setters are useless since the scope of your class attribute is ``public`. And Why? – akuma8 Jul 18 '18 at 21:57
  • @JBNizet in the intellij Run console, no stack trace is being produced, only the one error line. I'll try to run it from the terminal and see if a larger stack trace is produced. – mac Jul 18 '18 at 21:59
  • Interesting. Found this question by google. Have the same issue open like you right now, but with a different program. I think there is another bigger issue. – Anna Klein Jul 18 '18 at 22:01
  • @Andreas the underlying implementation of a Jackson deserialization is a LinkedHashMap, I think that's why it's complaining about that type of object. I don't know which method it's complaining about, but it only happens when that post call is made. – mac Jul 18 '18 at 22:02
  • @akuma8 I switched the fields to public to see if that would fix the problem, which it didn't. I forgot to switch them back. – mac Jul 18 '18 at 22:03
  • Could you share your pom.xml? – Pedro Jul 18 '18 at 22:06
  • Your code is working correctly for me. Can you show the cURL of your request? – Pedro Jul 18 '18 at 22:26
  • @Pedro I was using the Postman, but with the curl request `curl -H "Content-Type: application/json" -X POST -d '{"url": "http://google.com" }' http://localhost:8080/poster` I get the same issue – mac Jul 18 '18 at 22:32
  • Works like a charm for me. Are you sure this is all of your code? – Pedro Jul 18 '18 at 22:35
  • @Pedro this is all my code, I'll try it on a different machine – mac Jul 18 '18 at 22:53

3 Answers3

4

After Analyzing your problem, I found some cases where this issue can arise. Those are given bellow:

  1. Inner Class:

If your class TestEntity is Inner class of your endpoint. Just transfer your TestEntity from Inner class to a separate class and run your code, it will work.

  1. Support Inner Class:

If you want to support inner class a RequestBody then make TestEntity class as static, this will solve your problem.

  1. Spring dependency configuration:

If still not solved your problem, check your dependency on pom.xml. May be you are not adding dependency on proper way. For this you can view this answer . Or you can add jackson explicitly in your pom.xml file.

Dependencies are:

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

Hope this will solve your problem :)

If still not solved your problem, check some youtube video or some blog site or download some open-source project from github.

Thanks :)

Related links: Spring @Requestbody not mapping to inner class

Md. Sajedul Karim
  • 6,263
  • 3
  • 47
  • 77
2

Try to specify that your method consumes JSON. Change your annotation:
@RequestMapping(value = "/poster", method = RequestMethod.POST)
to

@PostMapping(value = "/poster",
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
            produces = MediaType.TEXT_HTML)

The main part here that you specify that you accept your input to be JSON. Not sure what type you return but you can specify the appropriate type or remove the "produces" part. The main part is to specify what your input is

Michael Gantman
  • 4,318
  • 1
  • 12
  • 31
0

Ideally this code should work but give a try by adding below dependency in pom.xml

<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.5.0</version>
</dependency>
Alien
  • 11,017
  • 3
  • 29
  • 45