【问题标题】:In JSON serialization howto ignore some of Class1 field(s) in case Class1 is a field of Class2?在 JSON 序列化中,如果 Class1 是 Class2 的字段,如何忽略一些 Class1 字段?
【发布时间】:2017-11-11 19:46:15
【问题描述】:

我在 stackoverflow 和 google 上搜索了这个问题,但找不到任何合适的答案。

如何忽略对象内对象的字段?

我认为举个例子会更容易理解:

(编者注,标题中:Class1=EngineClass2=Car 的字段)

class Car {
    Integer id;
    Integer numberOfWheels;
    Engine engine;
}   

class Engine {
    Integer id;
    String name;
    String producer;
    Integer horsePower;
    Integer weight; 
}

Car JSON 应包含所有字段,但 Car 对象中的 Engine 对象应限制为 id, name, producer

{
  "id":1,
  "numberOfWheels":4,
  "engine": {
    "id":1,
    "name":"some engine"
    "producer":"some engine producer"
  }
}

但是,引擎 JSON 应该包含所有字段 id, name, producer, horsePower, weight

{
    "id":1,
    "name":"some engine"
    "producer":"some engine producer"
    "horsePower":250
    "weight":500
}

只是为了澄清。 horsePowerweight 字段只能在 Car 生成的 JSON 中被忽略。

【问题讨论】:

  • 可以使用gson还是需要依赖Spring json库?不熟悉 Spring 及其 json 处理,Spring 使用什么 json 实现?
  • 我可以使用gson,我不必只坚持使用spring。我只是在寻找最佳实践和类型安全的解决方案。

标签: java json serialization gson


【解决方案1】:

看看gsons JsonSerializerExclusionStrategy。可能不是最简洁的方法 - 尤其是与您自己的解决方案相比 - 但总的来说是一个不错的选择。

要使Car 有一些特殊处理,请创建JsonSerializer 喜欢

public class CarSerializer implements JsonSerializer<Car> {
    private final Gson gson = new GsonBuilder()
            .addSerializationExclusionStrategy(new FieldExclusionStrategy()).create();

    @Override
    public JsonElement serialize(Car arg0, Type arg1, JsonSerializationContext arg2) {
        return new JsonParser().parse(gson.toJson(arg0));
    }
}

上面有自己的gson 只处理Car 而不会弄乱任何其他序列化。前面提到的将ExclusionStrategy 注册到它自己的私人用途,检查如果Cars 字段是Engine,那么Engine 中任何不需要的字段都会被跳过。

public class FieldExclusionStrategy  implements ExclusionStrategy {
    private Set<String> ignored = 
            new HashSet<String>(Arrays.asList( new String[]{"horsePower","weight"}));
    @Override
    public boolean shouldSkipField(FieldAttributes arg0) {
        if(arg0.getDeclaringClass().isAssignableFrom(Engine.class))
            if(ignored.contains(arg0.getName())) return true;
        return false;
    }       
    @Override
    public boolean shouldSkipClass(Class<?> arg0) { return false; }
}

它可以与注册JsonSerializer作为Car.class的类型适配器的gson一起使用:

Gson gson = new GsonBuilder().setPrettyPrinting()
      .registerTypeAdapter(Car.class, new CarSerializer()).create();

【讨论】:

  • 谢谢,这正是我要找的。该解决方案的唯一问题是它不是类型安全的,因为您必须将排除作为字符串提供。然而,我也很挣扎,看看如何做到类型安全,我想这没有完美的解决方案。我不确定创建 ExclusionStrategy 是否值得生气,因为这可能会为同一个对象但针对不同的包装器对象进行大量排除。你会推荐在我的解决方案上使用 ExclusionStrategy 吗?这不是针对特定问题,我只是想找到最佳实践解决方案
  • 是的,不是一直都是类型安全的,而且在错误检查方面也不完美。但我想你可以从这一点开始处理这部分,我相信它仍然是可能的。对您的解决方案而言,一生中只有一次是好的,但我倾向于更喜欢不干扰实体/模型的东西,换句话说,我的解决方案是对您的实体/模型的一种看法,您可以创建任意数量的视图而无需不再修改你的类,或者可能给它们带来一些讨厌的副作用。
  • 关于横切关注点的观点非常好。非常感谢你的帮助。有第二个意见总是很棒。
【解决方案2】:

我不耐烦了,决定创建一个临时解决方案,直到找到更好的方法。这个解决方案可能是也可能不是最佳实践,但我没有更好的解决方案。

如果有人发现这个问题并想知道解决方案,我决定发布我的临时解决方案。

我仍在寻找类型安全和最佳实践的解决方案,所以如果有人得到任何答案,请发布。无论您何时发布解决方案,我都会接受您的回答。

class Car {
    Integer id;
    Integer numberOfWheels;
    @JsonIgnore
    Engine engine;

    @JsonProperty("engine")
    public Map<String, Object> getEngineFormatted(){
        return engine == null ? null : engine.getFormatted();
    }
}   

class Engine {
    Integer id;
    String name;
    String producer;
    Integer horsePower;
    Integer weight; 

    public Map<String, Object> getFormatted(){
        Map<String, Object> map = new HashMap<>();

        map.put("id", id);
        map.put("name", name);
        map.put("producer", producer);

        return map;
    }
}

汽车 JSON:

{
  "id":1,
  "numberOfWheels":4,
  "engine": {
    "id":1,
    "name":"some engine"
    "producer":"some engine producer"
  }
}

引擎 JSON

{
    "id":1,
    "name":"some engine"
    "producer":"some engine producer"
    "horsePower":250
    "weight":500
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    相关资源
    最近更新 更多