json 集合(特别是集合)的自定义序列化程序/反序列化程序

o8x7eapl  于 2023-01-18  发布在  其他
关注(0)|答案(2)|浏览(161)

我想写一个自定义的序列化器,当它遇到一个集合的null值时,将它序列化为空集。我想将它与一个反序列化器配对,反序列化器将空集反序列化回null。如果集合有元素,它可以正常地序列化/反序列化。
我写过几个反序列化器,它们工作得很好,但是我在那里使用的方法似乎不适用于集合。例如,我写了以下代码来将空字符串转换为null:

JsonNode node = p.readValueAsTree();        
        String text = (Objects.isNull(node) ? null : node.asText());
        if (StringUtils.isEmpty(text)) {
            return null;
        }

我认为这不会起作用,因为JsonNode没有asSet()方法。
我在网上找到了一些看起来很有前途的例子,但似乎所有使用集合的例子都涉及到使用集合内部的元素,而不是集合本身。
到目前为止,我一直在手工编写这个过程,但我相信有一个更好的方法来处理它。
我正在通过反复试验来弄清楚它,所以任何例子、想法或建议都将不胜感激。
我觉得应该是这样的:

@JsonComponent
public class SetDeserializer extends Std???Deserializer<Set<?>> {
    
    public SetDeserializer() {
        super(Set.class);
    }

    @Override
    public Set<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = p.readValueAsTree();        
        Set<?> mySet = (Objects.isNull(node) ? null : node.asSet());
        if (CollectionUtils.isEmpty(mySet)) {
            return null;
        }
        return super().deserialize(p, ctxt);
    }

}
6yoyoihd

6yoyoihd1#

使用ObjectMapper非常简单。

public static List<String> deserializeStringArray(JsonNode node) throws IOException
{
  ObjectMapper mapper = new ObjectMapper();
  boolean isArrayNode = Objects.nonNull(node) && node.isArray();

  if (isArrayNode && !node.isEmpty()) {
    ObjectReader reader = mapper.readerFor(mapper.getTypeFactory().constructCollectionType(List.class, String.class));
    return reader.readValue(node);
  }
  else if (isArrayNode && node.isEmpty()) {
    return Collections.emptyList();
  }
  else {
    return null;
  }
}

首先验证节点是否为数组且不为空,返回nodes元素的List,但如果列表为空数组节点,则返回空列表,如果不是arrayNode,则返回null。
根据您的要求,我不确定数组列表的内容是空的(即null)还是json节点本身应该为null,如果JsonNode本身应该为null,那么您可以很容易地修改它,当它为null时返回一个空列表:

public static List<String> deserializeStringArray(JsonNode node) throws IOException
{
  ObjectMapper mapper = new ObjectMapper();
  if (Objects.nonNull(node) && node.isArray()) {
    ObjectReader reader = mapper.readerFor(mapper.getTypeFactory().constructCollectionType(List.class, String.class));
    return reader.readValue(node);
  }
  else {
    return Collections.emptyList();
  }
}

您可以通过以下方式对此进行测试

JsonNode arrayNode = mapper.createArrayNode().add("Bob").add("Sam");
System.out.println(deserializeStringArray(arrayNode));

JsonNode emptyArrayNode = mapper.createArrayNode();
System.out.println(deserializeStringArray(emptyArrayNode));

下面介绍如何使用上面的代码将对象反序列化为动物数组

@Component
public class AnimalDeserializer extends JsonDeserializer<Animal>
{
  ObjectMapper mapper;
  @Override
  public Animal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException
  {
    mapper = (ObjectMapper) p.getCodec();
    JsonNode node = p.getCodec().readTree(p);

    JsonNode arrayNode = node.get("myArrayField");

    List<Animal> animals = deserializeAnimalArray(arrayNode);

    return animals;
  }

  public List<Animal> deserializeAnimalArray(JsonNode node) throws IOException
  {
    boolean isArrayNode = Objects.nonNull(node) && node.isArray();

    if (isArrayNode && !node.isEmpty()) {
      ObjectReader reader = mapper.readerFor(mapper.getTypeFactory().constructCollectionType(List.class, String.class));
      return reader.readValue(node);
    }
    else if (isArrayNode && node.isEmpty()) {
      return Collections.emptyList();
    }
    else {
      return null;
    }
  }
}

您可以反转此操作以获得JsonNode。
编辑:添加了一个工作的反序列化器示例

iqxoj9l9

iqxoj9l92#

要使其按要求工作:

  • nullSet序列化为空JSON Array[]
  • 将空的JSON Array[]反序列化为null
  • 配置为全局

我们需要同时使用:

  • com.fasterxml.jackson.databind.JsonSerializer以生成空的JSON Array[]
  • 将空的SetList转换为null
  • com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector为所有属性注册串行器和转换器。

以下示例显示了上述所有组件及其使用方法:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.util.StdConverter;
import lombok.Data;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;

public class SetApp {
    public static void main(String[] args) throws JsonProcessingException {
        var mapper = JsonMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .annotationIntrospector(new EmptyAsNullCollectionJacksonAnnotationIntrospector())
                .build();

        var json = mapper.writeValueAsString(new CollectionsPojo());
        System.out.println(json);
        var collectionsPojo = mapper.readValue(json, CollectionsPojo.class);
        System.out.println(collectionsPojo);
    }
}

class EmptyAsNullCollectionJacksonAnnotationIntrospector extends JacksonAnnotationIntrospector {

    @Override
    public Object findNullSerializer(Annotated a) {
        if (Collection.class.isAssignableFrom(a.getRawType())) {
            return NullAsEmptyCollectionJsonSerializer.INSTANCE;
        }
        return super.findNullSerializer(a);
    }

    @Override
    public Object findDeserializationConverter(Annotated a) {
        if (List.class.isAssignableFrom(a.getRawType())) {
            return EmptyListAsNullConverter.INSTANCE;
        }
        if (Set.class.isAssignableFrom(a.getRawType())) {
            return EmptySetAsNullConverter.INSTANCE;
        }
        return super.findDeserializationConverter(a);
    }
}

class NullAsEmptyCollectionJsonSerializer extends JsonSerializer<Object> {

    public static final NullAsEmptyCollectionJsonSerializer INSTANCE = new NullAsEmptyCollectionJsonSerializer();

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartArray();
        gen.writeEndArray();
    }
}

class EmptySetAsNullConverter extends StdConverter<Set<?>, Set<?>> {

    public static final EmptySetAsNullConverter INSTANCE = new EmptySetAsNullConverter();

    @Override
    public Set<?> convert(Set<?> value) {
        if (CollectionUtils.isEmpty(value)) {
            return null;
        }
        return value;
    }
}

class EmptyListAsNullConverter extends StdConverter<List<?>, List<?>> {

    public static final EmptyListAsNullConverter INSTANCE = new EmptyListAsNullConverter();

    @Override
    public List<?> convert(List<?> value) {
        if (CollectionUtils.isEmpty(value)) {
            return null;
        }
        return value;
    }
}

@Data
class CollectionsPojo {
    private List<Integer> nullList;
    private List<Integer> emptyList = List.of();
    private List<Integer> listOfOne = List.of(1);
    private Set<String> nullSet;
    private Set<String> emptySet = Set.of();
    private Set<String> setOfOne = Set.of("One");
}

以上代码打印:
x一个一个一个一个x一个一个二个x
另见:

相关问题