java - JSON:InvalidFormatException:无法从字符串值构造 int 实例

标签 java json rest jackson

我有一个奇怪的问题,当服务器通过 REST 接收 JSON 时,Jackson 尝试将字符串转换为整数:

BlockquoSchwerwiegend: The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of int from String value 'before': not a valid Integer value at [Source: org.apache.catalina.connector.CoyoteInputStream@3916f0; line: 1, column: 182] (through reference chain: com.entities.SectionRelation["listLinkLabel"]->java.util.HashSet[0]->com.entities.LinkLabel["linkLabel"]) at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55) at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:883) at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseInteger(StdDeserializer.java:411) at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:289) at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:271) at com.fasterxml.jackson.databind.deser.impl.ObjectIdValueProperty.deserializeSetAndReturn(ObjectIdValueProperty.java:85) at com.fasterxml.jackson.databind.deser.impl.ObjectIdValueProperty.deserializeAndSet(ObjectIdValueProperty.java:77) at com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.findDeserializeAndSet(BeanPropertyMap.java:285) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:335) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeWithObjectId(BeanDeserializerBase.java:1045) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:240) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:212) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25) at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:523) ...

这是应该出现错误的实体:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

/**
 * The label name is unique and is therefore the 
 * primary key.
 */
@Entity
@JsonIdentityInfo(
        generator = ObjectIdGenerators.IntSequenceGenerator.class,
        property = "linkLabel")
public class LinkLabel implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @Column(name = "LinkLabel")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private String linkLabel;

    @JsonIgnore
    @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinTable(
       name="LINKLABEL_LINKSET",
       joinColumns={@JoinColumn(name="LINKLABEL_ID", referencedColumnName="LinkLabel")},
       inverseJoinColumns={@JoinColumn(name="LINK_LABEL_SET_ID", referencedColumnName="id")})
    private Set<LinkSet> linkSet = new HashSet();


    public String getLinkLabel() {
       return linkLabel;
    }

    public void setLinkLabel(String linkLabel) {
       this.linkLabel = linkLabel;
    }

    public Set<LinkSet> getLinkSet() {
       return linkSet;
    }

    public void addLinkSet(LinkSet linkSet) {
       this.linkSet.add(linkSet);
    }
}

这是服务器发送的 JSON 示例:

{
    "links": [{
            "id": 2,
            "section1": {
                ...
            },
            "section2": {
                ...
            },
            "listLinkLabel": [{
                    "linkLabel": 1,
                    "linkLabel": "after"
                }]
        }, {
            "id": 5,
            "section1": {
                ...
            },
            "section2": {
                ...
            },
            "listLinkLabel": [{
                    "linkLabel": 2,
                    "linkLabel": "before"
                }, {
                    "linkLabel": 3,
                    "linkLabel": "overlap"
                }, 1]
        }, {
            "id": 3,
            "section1": {
                ...
            },
            "section2": {
                ...
            },
            "listLinkLabel": [3]
        }
}

这是前端的负责片段:

this.addLink = function(source, target) {

               var JSONTemplate = {
                    "id":null,
                    "section1":{
                        ...
                    },
                    "section2":{
                        ...
                    },
                    "listLinkLabel":[{
//                            "linkLabel": 1
//                            ,
                            "linkLabel": "before"
                    }]
                };
                $http.post('service/sectionrelation', JSON.stringify(JSONTemplate));
}

我不明白为什么 jackson 试图将“linkLabel”“之前”转换为整数,当类型明确是字符串时,即使 @JsonFormat 也不会改变任何内容。只有 ""linkLabel": 1"不会引起错误,但必须有可能只发送 ""linkLabel": "before""。这对我来说似乎非常基本和简单,因为这是实体的正常表示。

在 pom.xml 中,Jackson 使用的是 2.6.3,GlassFish 4.1 是应用程序服务器。

最佳答案

每个 JSON 对象中有两个名为“linkLabel”的属性。如果您希望标准 JSON 解析器正确提取 JSON 对象中的属性名称,那么它们必须是唯一的。

将要发生的情况是 JSON 解析器将(默默地)忽略其中一个属性。例如:

    "listLinkLabel": [{
            "linkLabel": 1,
            "linkLabel": "after"
    }]

假设第一个属性被忽略,您的代码将尝试将 "after" 转换为整数......这将失败。

基本上,您的 JSON(语义上)格式错误,您需要更正生成它的任何内容。


更新 - 我想我已经弄清楚为什么 Jackson 会生成格式错误的 JSON。你有:

@JsonIdentityInfo(
    generator = ObjectIdGenerators.IntSequenceGenerator.class,
    property = "linkLabel")

还有

@Column(name = "LinkLabel")
@GeneratedValue(strategy = GenerationType.AUTO)
private String linkLabel;

换句话说,您已经告诉 Jackson 1) 有一个类型为 int 且名称为 linkLabel 的 id 属性,2) 有一个名为 的属性linkLabel,其类型为String

Jackson 对这种矛盾的信息感到有点困惑,并假设您已指定有两个名为 linkLabel 的不同属性...这不起作用1 .

您还>>似乎<<尝试使用linkLabel作为数据字段(包含非整数内容),这也是有问题的2

解决方案:要么删除 @JsonIdentityInfo 注释,要么将其更改为使用不同的属性名称,并使用正确的 Java 类型声明相应的 Java 字段。


1 - 它不适用于 Jackson 解析器...但您可以使其与自定义解析器一起使用。因此, jackson 有一个(微不足道的)理由这样做,而不是将其视为错误。

2 - jackson 不可能解决这个问题......

关于java - JSON:InvalidFormatException:无法从字符串值构造 int 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34561511/

相关文章:

带有 Spring 参数的 Java Akka Actors

Java Swing ContentPane 令人困惑的语句

java - 如何组织 Apache Spark 项目

security - Web API 身份验证和授权 (OAuth)

java - 如何在java中过滤对象的列表变量?

不带存储的 Python Django Rest Post API

javascript - 使用JSON填充列表项

javascript - 从 json 响应中解析动态 json 对象

java - 访问受 OAuth 安全保护的 Rest 服务的最佳方式是什么?

rest - Kong - 如何将 api 与特定的 jwt 消费者关联