Не мапится объект из POST запроса

352
25 августа 2018, 04:20

Моя задача состоит в том, чтобы создать post запрос, получить из него объект Item и сохранить его в базу данных Oracle. Для эмуляции запроса я использую Postmen и создаю в нём такой вот запрос:

Использую библиотеку для работы с jackson:

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

Класс сущности:

import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "ITEM")
public class Item {
    private Long id;
    private String name;
    private Date dateCreated;
    private Date lastUpdateDate;
    private String description;
    public Item() {
    }
    public Item(String name, Date dateCreated, Date lastUpdateDate, String description) {
        this.name = name;
        this.dateCreated = dateCreated;
        this.lastUpdateDate = lastUpdateDate;
        this.description = description;
    }
    @Id
    @SequenceGenerator(name = "IT_SQ", sequenceName = "ITEM_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "IT_SQ")
    public Long getId() {
        return id;
    }
    @Column(name = "NAME")
    public String getName() {
        return name;
    }
    @Column(name = "DATE_CREATED")
    public Date getDateCreated() {
        return dateCreated;
    }
    @Column(name = "LAST_UPDATE_DATE")
    public Date getLastUpdateDate() {
        return lastUpdateDate;
    }
    @Column(name = "DESCRIPTION")
    public String getDescription() {
        return description;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setDateCreated(Date dateCreated) {
        this.dateCreated = dateCreated;
    }
    public void setLastUpdateDate(Date lastUpdateDate) {
        this.lastUpdateDate = lastUpdateDate;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    @Override
    public String toString() {
        return "Item{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", dateCreated=" + dateCreated +
                ", lastUpdateDate=" + lastUpdateDate +
                ", description='" + description + '\'' +
                '}';
    }
}

Метод doPost:

import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@WebServlet(urlPatterns = "/test")
public class MyServlet extends HttpServlet {
    private ItemDAO itemDAO = new ItemDAO();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws IOException {
        //передать параметр из строки браузера в метод
        //найти по параметру объект в базе
        //вернуть объект в строковом представлении в браузер
        //String id = req.getParameter("param");
        //long idItem = Long.parseLong(id);
        //ItemDAO itemDAO = new ItemDAO();
        //itemDAO.findById(Long.parseLong(req.getParameter("param")));
        resp.getWriter().println(itemDAO.findById(Long.parseLong(req.getParameter("param"))).toString());
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{
        //считать данные из запроса
        //по ключам промапить объект
        //сделать валидацию, проверить есть ли объект с таким айди в базе
        //сохранить объект в базу
        StringBuilder stringBuilder = new StringBuilder();
        String line = null;
        BufferedReader reader = req.getReader();
        while ((line = reader.readLine()) != null){
            stringBuilder.append(line);
        }
        String json = stringBuilder.toString();
        System.out.println("Input string - " + json);
        ObjectMapper objectMapper = new ObjectMapper();
        Item item = objectMapper.convertValue(json, Item.class);
        System.out.println("Object after mapping: " + item);

    }

Запускаю, чтобы проверить как мапится объект и получаю ошибку:

06-Jul-2018 11:35:38.841 SEVERE [http-nio-8080-exec-5] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [MyServlet] in context with path [] threw exception
 java.lang.IllegalArgumentException: Can not instantiate value of type [simple type, class Item] from String value ('{    "name":"Item1",    "dateCreated":"04.07.2018",    "lastUpdateDate":"05.07.2018",    "description":"description1"}'); no single-String constructor/factory method
 at [Source: N/A; line: -1, column: -1]
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3459)
    at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:3378)
    at MyServlet.doPost(MyServlet.java:53)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1385)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class Item] from String value ('{    "name":"Item1",    "dateCreated":"04.07.2018",    "lastUpdateDate":"05.07.2018",    "description":"description1"}'); no single-String constructor/factory method
 at [Source: N/A; line: -1, column: -1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:878)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:281)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:284)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1176)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:145)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
    at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3454)
    ... 26 more

Подскажите, что делаю не так и как исправить мою ошибку, чтобы создавался объект Item.

Answer 1

Вам нужна статическая функция, объявленная в классе Item, которая будет принимать строку. Она должна быть помечена аннотацией @JsonCreator.

@JsonCreator
public static Item сreateFromJson(String jsonString) {
  ObjectMapper mapper = new ObjectMapper();
  Item item = null;
  try {
    item = mapper.readValue(jsonString, Item.class);
  } catch (IOException e) {
    e.printStackTrace();
  }
  return item;
}

Тогда можно будет воспользоваться readValue

Item item = objectMapper.readValue(json, Item.class);

Если хотите использовать convertValue, то придётся создать конструктор, в котором нужно будет присвоить значения из json, использовав тот же readValue.

READ ALSO
File is read-only. Правка файла в библиотеке мавена

File is read-only. Правка файла в библиотеке мавена

Процесс отладки показывает, что вызов с фронта обрабатывается классами из external libraries в maven

183
автоматизация java selenium webdriver

автоматизация java selenium webdriver

после запуска, открывается страница с хромом, в поле куда должны вписываться символы отget(), написано "data:,"

291
Для чего нужен tools.jar?

Для чего нужен tools.jar?

Разбирая пример написания класса Pair, столкнулся с тем, что такой класс уже реализован как comsun

199
Reconnect to AccessibilityService / переподключение к AccessibilityService

Reconnect to AccessibilityService / переподключение к AccessibilityService

Есть android-приложение, которое использует AccessibilityServiceПосле разрешения юзера приложение коннектится к сервису и работает с ним

188