Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring tries to deserialize to LinkedHashMap instead of POJO

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>
like image 562
mac Avatar asked Jul 18 '18 21:07

mac


2 Answers

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

like image 135
Md. Sajedul Karim Avatar answered Oct 17 '22 00:10

Md. Sajedul Karim


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

like image 43
Michael Gantman Avatar answered Oct 17 '22 01:10

Michael Gantman