Spring dynamically封装一个json可以是List也可以只是一个Object

jm2pwxwz  于 5个月前  发布在  Spring
关注(0)|答案(4)|浏览(64)

我创建了一个示例类,并响应于示例化,但这是需要修复的同一问题。响应可以是带对象的数组或just an Object。需要动态示例化

public record  MainClass(
  //the response can either be array or not array
  @JsonProperty("Relation") List<Relation> relation
){

 
}

public record  Relation(
   String relation,
   String Id,
){

 
}

字符串
当响应为数组Working时进行初始化
响应

{
 "Relation": [
          {
            "url": "https://sample.com",
            "Id": "77"
          }
        ]
        
}


如果响应不是数组This need to be fix,则执行初始化
响应

{
 "Relation":{
            "url": "https://sample.com",
            "Id": "77"
          }
        
        
}

gev0vcfq

gev0vcfq1#

另一种选择是为属性提供两个setter。

public class RelationWrapper
   private String id;
   private List<Relation> relation;

   public void setRelation(Relation relation) {
      this.relation = relation == null ? null : List.of(relation);
   }

   public void setRelation(List<Relation> relation) {
      this.relation = relation;
   }

   public List<Relation> getRelation() {
      return relation;
   }
}

字符串
这也可以用两个构造函数来完成

public class RelationWrapper
   private final String id;
   private final List<Relation> relation;

   @ConstructorProperties({"id", "relation"})
   public RelationWrapper(String id, List<Relation> relation) {
      this.id = id;
      this.relation = relation;
   }

   @ConstructorProperties({"id", "relation"})
   public RelationWrapper(String id, Relation relation) {
      this.id = id;
      this.relation = relation == null ? null : List.of(relation);
   }

   // getters
}

sq1bmfud

sq1bmfud2#

我认为你需要使用JsonNode来表示值,因为它可以表示任何值(数字,字符串,数组或对象)

public class RelationWrapper {
   private String id;
   private JsonNode relation;

   // getters & setters
}

public class Relation {
   private String id;
   private String url;

   // getters & setters
}

个字符
看到

  • ObjectMapper.valueToTree(Object)
  • ObjectMapper.treeToValue(TreeNode,Class)
  • JsonNode
cgfeq70w

cgfeq70w3#

你应该写自定义的std封装器,首先修改你的 Package 器来处理这两个

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RelationContainer {
  
  private Relation relation;
  private List<Relation> relations;
}

字符串
然后创建自定义std解析器:

public class RelationStdDeserializer extends StdDeserializer<RelationContainer> {
  
  public RelationStdDeserializer() {
    super(RelationContainer.class);
  }

  @Override
  public RelationContainer deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
    var objectCodec = jsonParser.getCodec();
    var jsonTree = objectCodec.readTree(jsonParser);
    if(jsonTree instanceof NullNode){
      return null;
    } else if (jsonTree instanceof ObjectNode objectNode) {
      var relationNode = objectNode.get("relations");
      if(relationNode instanceof NullNode){
        return new RelationContainer(null, null);
      } else if (relationNode instanceof ObjectNode jsonObject) {
        var relation = traverseNode(jsonObject, objectCodec, new TypeReference<Relation>() {
        });
        return new RelationContainer(relation, null);
      } else if (relationNode instanceof ArrayNode arrayObject) {
        var relations = traverseNode(arrayObject, objectCodec, new TypeReference<List<Relation>>() {
        });
        return new RelationContainer(null, relations);
      }
    }
    throw new IOException("Failed to read relations");
  }
  
  private <T> T traverseNode(JsonNode jsonNode, ObjectCodec objectCodec, TypeReference<T> typeReference) throws IOException {
    try(var jsonParser = jsonNode.traverse(objectCodec)){
      return objectCodec.readValue(jsonParser, typeReference);
    }
  }
}


最后在对象Map器bean中注册验证器:

@Bean
  public ObjectMapper objectMapper(){
    var objectMapper = new ObjectMapper();
    var relationModule = new SimpleModule();
    relationModule.addDeserializer(RelationContainer.class, new RelationStdDeserializer());
    return objectMapper;
  }

ijxebb2r

ijxebb2r4#

在Java中处理JSON数据时,您面临的问题是一个常见的问题,特别是当JSON的结构不一致时。在您的情况下,“Relation”字段可以是JSON数组或单个JSON对象。这种不一致性对数据表示提出了挑战。
您当前使用Jackson的@JsonProperty注解的方法是正确的,但需要对其进行调整以处理JSON结构中的可变性。下面是处理这种情况的最先进方法:
首先)**泛型的类型引用:**你可以使用Jackson的泛型类型引用来处理这个问题。例如,你可以尝试将类型化为List,如果失败(由于JsonProcessingException),只使用Relation再试一次。
然后)**可选 Package 器:**在某些情况下,使用Java的Optional类作为对象的 Package 器可能有助于处理JSON字段的可空性和存在性。

第一步:创建Wrapper类

public class RelationWrapper {

    private Optional<List<Relation>> relationsList;
    private Optional<Relation> singleRelation;

    public RelationWrapper(List<Relation> relationsList) {
        this.relationsList = Optional.ofNullable(relationsList);
        this.singleRelation = Optional.empty();
    }

    public RelationWrapper(Relation singleRelation) {
        this.singleRelation = Optional.ofNullable(singleRelation);
        this.relationsList = Optional.empty();
    }

    // Getters
    // Setter
}

字符串

第二步:实现自定义编译器

public class RelationDeserializer extends JsonDeserializer<RelationWrapper> {
    
    @Override
    public RelationWrapper deserialize(JsonParser jsonParser, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {

        JsonNode node = jsonParser.getCodec().readTree(jsonParser);

        try {
            // Attempt to deserialize as List<Relation>
            List<Relation> relations = jsonParser.getCodec().treeToValue(node, new TypeReference<List<Relation>>() {});
            return new RelationWrapper(relations);

        } catch (JsonProcessingException e) {
            // If it fails, deserialize as a single Relation object
            Relation relation = jsonParser.getCodec().treeToValue(node, Relation.class);
            return new RelationWrapper(relation);
        }
    }
}

最后一步:使用自定义编译器

最后,你需要告诉Jackson在格式化Relation字段时使用这个自定义的格式化器。你可以通过在MainClass中用@JsonDeserialize注解Relation字段来做到这一点:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.annotation.JsonProperty;

public class MainClass {

    @JsonDeserialize(using = RelationDeserializer.class)
    @JsonProperty("Relation")
    private RelationWrapper relation;

    // Constructor, getters, and setters
    public MainClass(RelationWrapper relation) {
        this.relation = relation;
    }

    public RelationWrapper getRelation() {
        return relation;
    }
}


该解决方案提供了一种灵活而优雅的方式来对JSON进行封装,其中特定字段的结构可能会有所不同。JSON Wrapper中的可选 Package 器可以清楚轻松地检查您是否有一个关系列表或单个关系。

相关问题