如何使用String字段将带有数组字段的JSON序列化为对象?

时间:2017-01-24 09:48:38

标签: java json serialization jackson

我有一个像

这样的JSON对象
{
  "id" : "1",
  "children" : ["2","3"]
}

我有一个Java对象(省略了构造函数,getter和setter):

public class Entity {
    public String id;
    public String children;
}

我希望使用Jackson代码将此JSON反序列化为我的Java对象:

Entity entity = mapper.readValue(json, Entity.class);

但是得到以下错误:

Can not deserialize instance of java.lang.String out of START_ARRAY token

如何在不更改children字段类型的情况下解决问题?

children字段应具有以下值:["2","3"]

3 个答案:

答案 0 :(得分:2)

创建自定义反序列化程序

创建自定义反序列化器以获取原始JSON值。您可以根据需要选择以下实现之一:

  1. 它将按原样为您提供JSON ,即保留所有空格和标签:
  2. public class RawJsonDeserializer extends JsonDeserializer<String> {
    
        @Override
        public String deserialize(JsonParser jp, DeserializationContext ctxt)
               throws IOException, JsonProcessingException {
    
            long begin = jp.getCurrentLocation().getCharOffset();
            jp.skipChildren();
            long end = jp.getCurrentLocation().getCharOffset();
    
            String json = jp.getCurrentLocation().getSourceRef().toString();
            return json.substring((int) begin - 1, (int) end);
        }
    }
    
    1. 它将为您提供没有额外空格和标签的JSON:
    2. public class RawJsonDeserializer extends JsonDeserializer<String> {
      
          @Override
          public String deserialize(JsonParser jp, DeserializationContext ctxt)
                 throws IOException {
      
              JsonNode node = jp.getCodec().readTree(jp);
              ObjectMapper mapper = (ObjectMapper) jp.getCodec();
              return mapper.writeValueAsString(node);
          }
      }
      

      注释您的类以使用上面定义的反序列化器

      通过引用Entity属性并使用children引用上面定义的反序列化器来更改@JsonDeserialize类:

      public class Entity {
      
          public String id;
      
          @JsonDeserialize(using = RawJsonDeserializer.class)
          public String children;
      }
      

      解析JSON

      然后使用ObjectMapper解析JSON,Jackson将使用您的自定义反序列化器:

      String json = "{\"id\":\"1\",\"children\":[\"2\",\"3\"]}";
      
      ObjectMapper mapper = new ObjectMapper();
      Entity entity = mapper.readValue(json, Entity.class);
      

      children属性的值为["2","3"]

      有关详细信息,请查看此question

答案 1 :(得分:1)

将您的对象转换为JSON格式。
然后从JSON文件解组

public interface MarshallingSupport {
public String marshal(Object object);
public <T> T unmarshal(String s, Class<T> t);
}

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class JacksonJSONMarshallingSupport implements MarshallingSupport {

private final ObjectMapper mapper;

   public JacksonJSONMarshallingSupport(ObjectMapper mapper) {
       this.mapper = mapper;
       this.mapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
   }

    @Override
    public String marshal(Object object) {
       try {
            return mapper.writeValueAsString(object);
           } catch (JsonProcessingException ex) {
               throw new RuntimeException(ex);
           }
   }

   @Override
   public <T> T unmarshal(String s, Class<T> t) {
       try {
             T newObj = mapper.readValue(s, t);
             return newObj;
           } catch (IOException ex) {
               throw new RuntimeException(ex);
           }
   }
}

答案 2 :(得分:1)

接受@ Cassio的回答,如果你不想或你不能注释你的实体类,只需添加一些配置。

首先创建一个抽象类[for method annotation purpose you can create an interface, but in this case we will annotate a bean property so we create an abstract class, and if you also want to annotate a method in this abstract class you have to declare that method as abstract],就像Jackson配置的mime bean一样:

public abstract class EntityMixIn {

    @JsonDeserialize(using = RawJsonDeserializer.class)
    public String children;

}

现在,你必须告诉你的mapper采用这个mixin类,并且只是为了这个配置目的而像原始的Entity类一样:

mapper.addMixIn(Entity.class, EntityMixIn.class);