2016-01-02 15 views
1

我有當服務器收到通過REST一個JSON,傑克遜試圖將字符串轉換爲整數這個奇怪的問題:JSON:InvalidFormatException:不能從字符串值構造爲int的實例

BlockquoSchwerwiegend:本包含在MappableContainerException中的異常無法映射到響應,重新拋出到HTTP容器 com.fasterxml.jackson.databind.exc.InvalidFormatException:無法從String值'之前'構造int實例:不是有效的Integer值 at [Source:[email protected]; line:1,column:182](通過引用鏈: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.deserializeSetAndRet在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) 在com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140) 在com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:240) 在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)); 
} 

我不明白爲什麼傑克遜會嘗試把「LinkLabel的」「之前」到整數,當類型爲definetely一個字符串,即使@JsonFormat不會改變任何東西。只有「」linkLabel「:1」不會引發錯誤,但必須有可能只發送「」linkLabel「:」之前「」。這對我來說似乎非常基本和簡單,因爲這是實體的正常表示。

在pom.xml中使用的是Jackson 2.6.3,而GlassFish 4.1是應用程序服務器。

回答

2

在每個JSON對象中有兩個名爲「linkLabel」的屬性。 JSON對象中的屬性名稱必須是唯一,如果您希望它們通過標準JSON解析器正確提取。

將要發生的事情是其中一個屬性將被JSON解析器忽略(靜默)。例如:

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

假設第一屬性是忽略了一個,你的代碼然後嘗試"after"轉換爲整數...這將失敗。

基本上,你的JSON是(語義)畸形的,你需要糾正生成它的任何東西。


UPDATE - 我想我已經想通了,爲什麼傑克遜產生畸形的JSON。您有:

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

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

換句話說,你告訴傑克遜:1)有與int類型和名稱linkLabel一個id屬性,2)有一個名爲linkLabel屬性其類型爲String

Jackson對這個矛盾的信息有些困惑,並且假設你已經指定了兩個不同的屬性linkLabel ......它不起作用。

也出現>> < <將試圖使用linkLabel作爲數據字段(非整數的內容),而且也存在問題。

解決方案:要麼擺脫@JsonIdentityInfo註釋,或將其更改爲使用不同的財產名,並用正確的Java類型聲明相應的Java領域。


1 - 它不與傑克遜解析器工作...但你可以把它與一個自定義的解析器工作。因此,傑克遜有一個(微不足道的)理由來做這件事,而不是將其視爲錯誤。

2 - 沒有辦法,傑克遜能想出這一個...

+0

第一個附加的JSON是由服務器根據幾個在線json驗證器生成的。問題是接收和解析不發送。因此 ' 「listLinkLabel」:[{ // 「的LinkLabel」:1 //, 「的LinkLabel」: 「之前」 }]' 被列入,以指示該評論和未註釋的溶液不起作用,只有「」linkLabel「:1」,這沒有任何意義 – Rooky

+1

@Rooky:JSON可以被讀取,但是具有重複的鍵將導致很多問題,避免它,除非你想手動編碼解析器。您引用的錯誤信息並不令人意外,而且完全合理。 「linkLabel」被確定爲對象ID,並被定義爲整數。 – araqnid

+0

非常感謝,你真棒!我認爲這是正常的json標準來保存字符。 – Rooky

0

如果你使用谷歌的端點框架:請確保您的@Api註釋的@Named指定的任何參數無論作爲身體的一部分傳入的任何其他對象都是唯一的。如果您使用@Named參數「id」並且還有一個具有相同參數的對象,則終端將會感到困惑。

這似乎是在終結點執行的規範應在路徑和序列化值之間的差異的錯誤那些在身體:https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameter-object

例如,如果您有:

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 
    } 
} 

您將看到您的終端服務器拋出:

[INFO] INFO:在調用後臺方法 發生的異常[INFO] com.googl e.api.server.spi.response.BadRequestException:com.fasterxml.jackson.databind.exc.InvalidFormatException:無法從字符串值'EXAMPLEUUID'構造java.lang.Long實例:不是有效的Long值 [INFO]在[來源:N/A;行:-1,列:-1](通過引用鏈:com.example.package.MyData [「id」]) [INFO] at com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader .java:128)

端點框架看到@Named(「id」)thingId字段,並將其反序列化爲MyData,它不是按規範或期望的。簡單地重命名參數將解決這個問題:@Named(「thingId」)thingId。