65

ジャージーで構築され、AppEngineにデプロイされたRESTサービスがあります。RESTサービスは、application/jsonメディアタイプを消費する動詞PUTを実装します。データバインディングはJacksonによって実行されます。

動詞は、JSONで次のように表される企業と部門の関係を消費します

{"name":"myEnterprise", "departments":["HR","IT","SC"]}

クライアント側では、gsonを使用してJSON表現をJavaオブジェクトに変換します。次に、オブジェクトをRESTサービスに渡すと、正常に機能します。

問題:

JSON表現のコレクションにアイテムが1つしかない場合

{"name":"myEnterprise", "departments":["HR"]}

サービスはオブジェクトを逆シリアル化できません。

ATTENTION: /enterprise/enterprise: org.codehaus.jackson.map.JsonMappingException: 
Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token at 
[Source: org.mortbay.jetty.HttpParser$Input@5a9c5842; line: 1, column: 2

他のユーザーから報告されているように、解決策はフラグを追加することですACCEPT_SINGLE_VALUE_AS_ARRAY(たとえば、Jersey:ArrayListのインスタンスをStringから逆シリアル化することはできません)。ObjectMapperそれにもかかわらず、サービス側ではジャクソンによって透過的に作成されているため、私は制御していません。

質問:

ObjectMapper有効にするようにサービス側でを構成する方法はありますACCEPT_SINGLE_VALUE_AS_ARRAYか?注釈?web.xml

コードの詳細

Javaオブジェクト:

@XmlRootElement
public class Enterprise {
    private String name;
    private List<String> departments;

    public Enterprise() {}

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<String> getDepartments() {
        return departments;
    }
    public void setDepartments(List<String> departments) {
        this.departments = departments;
    }
}

RESTサービス側:

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/enterprise") 
    public Response putEnterprise(Enterprise enterprise,
            @Context HttpServletRequest req){
         ...
    }

クライアント側:

...
String jsonString = "{\"name\":\"myEnterprise\", \"departments\":[\"HR\"]}";
Enterprise enterprise = gson.fromJson(jsonString, Enterprise.class);
System.out.println(gson.toJson(enterprise));
response = webResource              
           .type(MediaType.APPLICATION_JSON)
           .put(ClientResponse.class,enterprise);
if (response.getStatus() >= 400) {
        throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
...
4

5 に答える 5

58

これは私の古い質問の解決策です:

この機能ContextResolverを有効にするために、自分で実装しました。DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY

package org.lig.hadas.services.mapper;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;

@Produces(MediaType.APPLICATION_JSON)
@Provider
public class ObjectMapperProvider implements ContextResolver<ObjectMapper>
{
   ObjectMapper mapper;

   public ObjectMapperProvider(){
       mapper = new ObjectMapper();
       mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
   }
   @Override
   public ObjectMapper getContext(Class<?> type) {
       return mapper;
   }
}

そして、web.xml私は自分のパッケージをサーブレット定義に登録しました...

<servlet>
    <servlet-name>...</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>...;org.lig.hadas.services.mapper</param-value>        
    </init-param>
    ...
</servlet>

...残りはすべて、ジャージ/ジャクソンによって透過的に行われます。

于 2013-04-17T23:19:23.360 に答える
28

この属性をObjectMapperインスタンスに設定すると、機能します。

objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
于 2016-03-27T08:12:35.007 に答える
22

やってみますか

[{"name":"myEnterprise", "departments":["HR"]}]

四角いブレースが重要なポイントです。

于 2013-04-09T10:10:24.040 に答える
15

Jackson 2.7.x +から、メンバー変数自体に注釈を付ける方法があります。

 @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
 private List<String> newsletters;

詳細はこちら:Jackson @JsonFormat

于 2019-05-22T12:40:58.520 に答える
6

エラーメッセージを検索してこの質問を見つけた人は、単一値フィールドの名前で型付きプロパティに@JsonProperty注釈を付けるなど、注釈を間違えた場合にもこのエラーを確認できます。List

@JsonProperty("someSingleValuedField") // Oops, should have been "someMultiValuedField"
public List<String> getMyField() { // deserialization fails - single value into List
  return myField;
}
于 2016-03-10T13:37:43.910 に答える