java JSON: InvalidFormatException: 无法从 String 值构造 int 的实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34561511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 23:03:16  来源:igfitidea点击:

JSON: InvalidFormatException: Can not construct instance of int from String value

javajsonrestHymanson

提问by Rooky

I have this weird problem that when the server receives a JSON via REST, Hymanson tries to convert a String into an Integer:

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

BlockquoSchwerwiegend: The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container com.fasterxml.Hymanson.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.Hymanson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55) at com.fasterxml.Hymanson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:883) at com.fasterxml.Hymanson.databind.deser.std.StdDeserializer._parseInteger(StdDeserializer.java:411) at com.fasterxml.Hymanson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:289) at com.fasterxml.Hymanson.databind.deser.std.NumberDeserializers$IntegerDeserializer.deserialize(NumberDeserializers.java:271) at com.fasterxml.Hymanson.databind.deser.impl.ObjectIdValueProperty.deserializeSetAndReturn(ObjectIdValueProperty.java:85) at com.fasterxml.Hymanson.databind.deser.impl.ObjectIdValueProperty.deserializeAndSet(ObjectIdValueProperty.java:77) at com.fasterxml.Hymanson.databind.deser.impl.BeanPropertyMap.findDeserializeAndSet(BeanPropertyMap.java:285) at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:335) at com.fasterxml.Hymanson.databind.deser.BeanDeserializerBase.deserializeWithObjectId(BeanDeserializerBase.java:1045) at com.fasterxml.Hymanson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) at com.fasterxml.Hymanson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:240) at com.fasterxml.Hymanson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:212) at com.fasterxml.Hymanson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25) at com.fasterxml.Hymanson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:523) ...

BlockquoSchwerwiegend:MappableContainerException 中包含的异常无法映射到响应,重新抛出到 HTTP 容器 com.fasterxml.Hymanson.databind.exc.InvalidFormatException:无法从字符串值“之前”构造 int 实例:无效[来源:org.apache.catalina.connector.CoyoteInputStream@3916f0; 的整数值;行:1,列:182](通过参考链:com.entities.SectionRelation["listLinkLabel"]->java.util.HashSet[0]->com.entities.LinkLabel["linkLabel"])在 com.fasterxml .Hymanson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55) at com.fasterxml.Hymanson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:883) at com.fasterxml.Hymanson.databind.deser.std.StdDeserializer .

This is the entity where the error is supposed to be:

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

import com.fasterxml.Hymanson.annotation.JsonFormat;
import com.fasterxml.Hymanson.annotation.JsonIdentityInfo;
import com.fasterxml.Hymanson.annotation.JsonIgnore;
import com.fasterxml.Hymanson.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);
    }
}

This is an example JSON which was sent by the server:

这是服务器发送的示例 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 is the responsible snippet of the frontend:

这是前端的负责片段:

this.addLink = function(source, target) {

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

I don't see why Hymanson tries to convert "linkLabel" "before" to an Integer, when the type is definetely a String, even @JsonFormat doesn't change anything. Only ""linkLabel": 1" evokes no errors , but there must be a possibility to send only ""linkLabel": "before"". This seems pretty basic and simple to me, because this is the normal representation of the entity.

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

In the pom.xml Hymanson is used 2.6.3 and GlassFish 4.1 is the application server.

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

采纳答案by Stephen C

You have two attributes called "linkLabel" in each of the JSON objects. Attribute names in a JSON object have to beunique if you want them to be extracted correctly by a standard JSON parser.

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

What is going to happen is that one of the attributes is going to be ignored (silently) by the JSON parser. For example:

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

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

Assuming that the first attribute is the one that is ignored, your code will then try to convert "after"to an integer ... which will fail.

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

Basically, your JSON is (semantically) malformed, and you need to correct whatever is generating it.

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



UPDATE- I think I have figured out why Hymanson is generating malformed JSON. You have:

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

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

and also

并且

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

In other words, you have told Hymanson that 1) there is a id attribute with type intand name linkLabel, 2) there is a property named linkLabelwhose type is String.

换句话说,您已经告诉Hyman逊 1) 有一个 id 属性的 typeint和 name linkLabel,2) 有一个名为linkLabel的属性,其类型为String.

Hymanson has gotten a bit confused by this contradictory information, and assumed that you have specified there are two distinct attributes called linkLabel... which doesn't work1.

Hymanson 对这个相互矛盾的信息感到有些困惑,并假设您已经指定了两个不同的属性,称为linkLabel... 这不起作用1

You also >>appear<< to be trying to use linkLabelas a data field (with non-integer content) and that is also problematic2.

您还 >>出现<< 试图linkLabel用作数据字段(具有非整数内容),这也是有问题的2

Solution: either get rid of the @JsonIdentityInfoannotation, or change it to use a distinctproperty name, and declare the corresponding Java field with the correct Java type.

解决办法:要么去掉@JsonIdentityInfo注解,要么改成使用不同的属性名,并用正确的Java类型声明对应的Java字段。



1 - It doesn't work with the Hymanson parser ... but you could make it work with a custom parser. Hence, there is a (tenuous) justification for Hymanson to do this rather than treating this as an error.

1 - 它不适用于 Hymanson 解析器……但您可以使用自定义解析器使其工作。因此,Hyman逊有一个(微弱的)理由这样做而不是将其视为错误。

2 - There is no way that Hymanson could figure this one out ...

2 - Hyman逊不可能弄清楚这一点......

回答by Chris

If you're using Google's Endpoints Framework: Be sure that any parameters specified in your @Api annotation's @Named are unique regardless of any other objects passed in as part of the body. If you use the @Named parameter "id" and also have an object with the same parameter, Endpoints will get confused.

如果您使用的是 Google 的 Endpoints Framework:请确保在 @Api 注释的 @Named 中指定的任何参数都是唯一的,无论作为主体的一部分传入的任何其他对象如何。如果您使用@Named 参数“id”并且还有一个具有相同参数的对象,端点将变得混乱。

This appears to be a bug in the Endpoints implementation as the specification should differentiate between serialized values in the path and those in the body: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameter-object

这似乎是 Endpoints 实现中的一个错误,因为规范应该区分路径中的序列化值和正文中的序列化值:https: //github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md #参数对象

For example, if you have:

例如,如果您有:

class MyData {
    private Long id;
    public Long getId(){return id;}
    public void setId(Long v){id = v;}
}


@Api( /* Your API stuff here */ )
class EndpointBase {

    @ApiMethod(
            name = "thingGet",
            httpMethod = "GET")
    public KnockerResponse thingGet(
            @Named("id") String thingId,
            MyData data
    )  {
        // Never executes
    }
}

You'll see your Endpoints server throw:

你会看到你的端点服务器抛出:

[INFO] INFO: exception occurred while calling backend method [INFO] com.google.api.server.spi.response.BadRequestException: com.fasterxml.Hymanson.databind.exc.InvalidFormatException: Can not construct instance of java.lang.Long from String value 'EXAMPLEUUID': not a valid Long value [INFO] at [Source: N/A; line: -1, column: -1] (through reference chain: com.example.package.MyData["id"]) [INFO] at com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader.java:128)

[INFO] INFO:调用后端方法时发生异常 [INFO] com.google.api.server.spi.response.BadRequestException:com.fasterxml.Hymanson.databind.exc.InvalidFormatException:无法构造 java.lang.Long 的实例来自字符串值“EXAMPLEUUID”:在 [来源:不适用;行:-1,列:-1](通过参考链:com.example.package.MyData["id"]) [INFO] 在 com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader.read(RestServletRequestParamReader.爪哇:128)

Endpoints Framework sees the @Named("id") thingId field and is de-serializing it into MyData, which is not per-spec or desired. Simply re-naming the parameter will fix this: @Named("thingId") thingId.

Endpoints Framework 看到 @Named("id") thingId 字段并将其反序列化为 MyData,这不是每个规范或所需的。只需重新命名参数即可解决此问题:@Named("thingId") thingId。