简体   繁体   English

Springboot中的某些字段未在JSON中解析/反序列化

[英]Some fields not getting parsed/deserialized in JSON in Springboot

I am using the below JSON to get parsed by my springboot code: 我正在使用下面的JSON通过springboot代码进行解析:

{
    "id" :123, 
    "Subject" : "English",
    "name": {
    "Firstname": "Hemant",
    "Middlename": "kumar", 
    "Lastname": "Mamod"
    }
}

But on parsing/deserializing it I am getting this in the object of Student: 但是在解析/反序列化时,我得到的是Student对象:

Student [id=123, Subject=null, name=Name [Firstname=null, Middlename=null, Lastname=null]] 学生[id = 123,主题=空,名称=名称[名字=空,中间名=空,姓氏=空]]

I aleady have public gettters & setters everywhere which makes every field eligible for deserialization. 我无处不在有公共吸气器和二传手,这使得每个领域都有反序列化的资格。 I am referring this - https://www.baeldung.com/jackson-field-serializable-deserializable-or-not 我指的是-https: //www.baeldung.com/jackson-field-serializable-deserializable-or-not

Below is the code snippet I am using: 以下是我正在使用的代码段:

Restcontroller: Restcontroller:

    package com.example.demo;
    import java.util.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.http.MediaType;
    import org.springframework.web.bind.annotation.*;


    @SpringBootApplication
    @RestController
    public class Demo1Application {


    @Autowired
    Student student;
    List<Student> students = new ArrayList<>();


    @RequestMapping(value="/saveStudent", method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE)
    public String savestudent (@RequestBody Student s1) {

        System.out.println(s1);
        return "success";
    }   


    public static void main(String[] args) {
        SpringApplication.run(Demo1Application.class, args);
        System.out.println("Hello");
    }
    }

Student Bean Class: 学生豆类:

package com.example.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Student {
    int id;
    String Subject;

    @Autowired
    @Qualifier("name")
    Name name;


    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getSubjects() {
        return Subject;
    }
    public void setSubject(String subject) {
        Subject = subject;
    }

    public void setName(Name name) {
        this.name = name;  
    }
    public Name getName() {  
        return name  ;
    }
@Override
public String toString() {
    return "Student [id=" + id + ", Subject=" + Subject + ", name=" + name + "]";
    }
}

Name Bean Class: 命名Bean类:

package com.example.demo;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("name")
public class Name {
    private String Firstname;
    private String Middlename;
    private String Lastname;

    public Name() {
        System.out.println("Name Object created");
    }

    public String getFirstname() {
        return Firstname;
    }
    public void setFirstname(String firstname) {
        Firstname = firstname;
    }
    public String getMiddlename() {
        return Middlename;
    }
    public void setMiddlename(String middlename) {
        Middlename = middlename;
    }
    public String getLastname() {
        return Lastname;
    }
    public void setLastname(String lastname) {
        Lastname = lastname;
    }

    public Name setfullname(String Fname, String Mname, String Lname) {
        Firstname = Fname;
        Middlename = Mname;
        Lastname = Lname;
        return this;
    }

    @Override
    public String toString() {
        return "Name [Firstname=" + Firstname + ", Middlename=" + Middlename + ", Lastname=" + Lastname + "]";
    }

}

PS - PS-

1.) On making the private fields as public , the code is working fine. 1.)在将私有字段设为public时,代码运行良好。 I made these fields as public - id , Subject , name, Firstname, Middlename, Lastname 我将这些字段设置为public-id,Subject,name,Firstname,Middlename,Lastname

2.) I already know that by adding below two in application.properties wil give me correct output: spring.jackson.deserialization.fail-on-unknown-properties=false spring.jackson.mapper.accept-case-insensitive-properties=true 2.)我已经知道,通过在application.properties中添加以下两个内容将为我提供正确的输出:spring.jackson.deserialization.fail-on-unknown-properties = false spring.jackson.mapper.accept-case-insensitive-properties =真正

I just want to know where exactly I am doing things wrong. 我只想知道我在哪里做错了。 I have public gettters & setters everywhere 我到处都有公共场所

Reformat your JSON input to have camel case keys: 重新格式化JSON输入以使用驼峰式大小写键:

{
    "id" :123, 
    "subject" : "English",
    "name": {
    "firstname": "Hemant",
    "middlename": "kumar", 
    "lastname": "Mamod"
    }
}

This is now working. 现在正在工作。 Fix was to keep Both the property name & JSON in lower case for fields to be correctly Deserialized as metioned by Jens, James and Kamil. 修复方法是将属性名称和JSON都保留为小写,以便按Jens,James和Kamil的建议正确反序列化字段。 I have Changed property names as follows: 我更改了属性名称,如下所示:

private String Subject;     -->  private String subject; 
private String Firstname;   -->  private String firstname;
private String Middlename;  -->  private String middlename;
private String Lastname;    -->  private String lastname;

Use the @JsonProperty annotation map the name of the property in json to the property name in java: 使用@JsonProperty批注将json中的属性名称映射到java中的属性名称:

@JsonProperty("Firstname")
private String firstname;
@JsonProperty("Middlename")
private String middlename;
@JsonProperty("Lastname")
private String lastname;

The reason for the json not getting accepted with the first character of attributes in upper case is because jackson library is resolving property names from getters and setters of the class corresponding to the json. json不被大写的属性的第一个字符接受的原因是因为jackson库正在从对应于json的类的getter和setter解析属性名称。 Jackson constructs property names by converting the leading characters of text following 'get' to lower case(from getter method in java side). Jackson通过将'get'之后的文本的前导字符转换为小写来构造属性名称(来自Java端的getter方法)。 For example: getSubject in the Student class is kept in a property set as 'subject'. 例如:Student类中的getSubject保留在设置为“ subject”的属性中。

When a post request is send with the json, attributes in the json is compared against the property set. 使用json发送发布请求时,会将json中的属性与属性集进行比较。 Only those attribute names that match this property set will have their values added from json to corresponding java attribute. 只有与该属性集匹配的那些属性名称才会将其值从json添加到相应的java属性。 When you do post request with json attribute name 'Subject',jackson won't deserialize this . 当您使用json属性名称“ Subject”发布请求时,jackson不会对此进行反序列化。 Since 'Subject' attribute name does not match with 'subject' in the property set. 由于“主题”属性名称与属性集中的“主题”不匹配。 That is why the null was coming initially for those attributes. 这就是为什么这些属性最初会为null的原因。

The above said is the default behaviour.To override this behavior you can map the java property to desired json attribute name by using @JsonProperty annotation: 上面说的是默认行为。要覆盖此行为,您可以使用@JsonProperty批注将java属性映射到所需的json属性名称:

@JsonProperty("Subject")
String Subject;

Otherwise use the json attribute name starting with lower case.For eg:'subject' instead of 'Subject' 否则请使用以小写字母开头的json属性名称。例如:用'subject'代替'Subject'

The conversion of leading chacracter case can be seen in com.fasterxml.jackson.databind.util.Beanutil class.The below method does this: 可以在com.fasterxml.jackson.databind.util.Beanutil类中看到主要的大写字母案例的转换。以下方法可以做到这一点:

protected static String legacyManglePropertyName(final String basename, final int offset)
    {
        final int end = basename.length();
        if (end == offset) { // empty name, nope
            return null;
        }
        // next check: is the first character upper case? If not, return as is
        char c = basename.charAt(offset);
        char d = Character.toLowerCase(c);

        if (c == d) {
            return basename.substring(offset);
        }
        // otherwise, lower case initial chars. Common case first, just one char
        StringBuilder sb = new StringBuilder(end - offset);
        sb.append(d);
        int i = offset+1;
        for (; i < end; ++i) {
            c = basename.charAt(i);
            d = Character.toLowerCase(c);
            if (c == d) {
                sb.append(basename, i, end);
                break;
            }
            sb.append(d);
        }
        return sb.toString();
    }

The property name comparison against json attribute can be found in the below code(deserializeFromObject function in com.fasterxml.jackson.databind.deser.BeanDeserializer class. I am not pasting the entire function as it is too long). 可以在下面的代码中找到与json属性的属性名称比较(com.fasterxml.jackson.databind.deser.BeanDeserializer类中的deserializeFromObject函数。由于时间太长,我没有粘贴整个函数)。 The variable p corresponds to Jsonparser and beanProperties is containing the propertynames resolved from getter and setter,deserializeAndSet method is setting json attribute value to the java bean: 变量p对应于Jsonparser,beanProperties包含从getter和setter解析的属性名,deserializeAndSet方法将json属性值设置为java bean:

 if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
            String propName = p.getCurrentName();
            do {
                p.nextToken();
                SettableBeanProperty prop = _beanProperties.find(propName);
                if (prop != null) { // normal case
                    try {
                        prop.deserializeAndSet(p, ctxt, bean);
                    } catch (Exception e) {
                        wrapAndThrow(e, bean, propName, ctxt);
                    }
                    continue;
                }
                handleUnknownVanilla(p, ctxt, bean, propName);
            } while ((propName = p.nextFieldName()) != null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM