【问题标题】:Remove a field from entity when passing to Jersey + Jackson传递给 Jersey + Jackson 时从实体中删除一个字段
【发布时间】:2015-01-08 14:13:47
【问题描述】:

我正在使用 Jersey + Jackson(内置于 Dropwizard)来创建一系列 Web 服务。我通过将对象传递给 Jersey 中的 Response 对象来直接映射 Json 中的对象:

myObject object = new myObject(fields...);
return Response.ok(object).build();

使用 JsonProperty("fieldName") 在 myObject 类中正确注释字段。

但是,如果我有一个需要存储到数据库的字段(例如:密码哈希),但我不想传递请求响应,那么在将实体传递给 Response 对象时如何删除该字段?

我不能用 JsonIgnore 注释该字段,否则当我将 Json 映射到数据库 (ElasticSearch) 时,该字段根本不会被序列化。

【问题讨论】:

    标签: java json jersey jackson dropwizard


    【解决方案1】:

    一种选择是简单地将字段设置为null。要将ObjectMapper配置为在字段为空时完全忽略JSON中的字段,您可以这样做

    @Override
    public void run(YourConfiguration configuration,
            Environment environment) throws Exception {
        ...
        environment.getObjectMapper().setSerializationInclusion(Include.NON_NULL);
    }
    

    顺便说一句,这个安全原因是使用 DTO(数据传输对象)的原因之一,这是一个额外的实体“视图”层,它将我们发送的表示与持久层(db 实体对象)分开。创建另一个具有相同/相似属性的对象似乎是多余的,但安全填充是值得的。

    此外,虽然还没有正式发布,Dropwizard 0.8.0 使用 Jersey 2,它引入了 Entity Filtering,它允许我们过滤掉我们不想发送的数据,而无需创建 DTO。只是想我会提到它。

    【讨论】:

    • 谢谢;我从未使用过实体过滤,但我认为这是实现我需要的最佳方式。您能否提供一个 Dropwizard 中的实体过滤示例(我使用的是 DW 0.8.0-rc1)?是否可以让实体过滤仅在单个资源/路由上工作,而不是在全局应用程序级别?
    • 我刚刚意识到它目前不支持杰克逊。我一直在考虑尝试实现一些东西,但这远非微不足道。我说只是使用 DTO 或将其设置为空。如果你想要一个更优雅的解决方案(不必在资源方法中将字段设置为 null),你可以使用 JAX-RS 拦截器,但在这样做之前我会三思而后行。像密码这样安全的东西,我会尽可能远离最终过程
    【解决方案2】:

    您应该同时使用 JsonIgnore 和 JsonProperty 来实现这一点。

      public class User {
    
      private String name;
      private String password;
    
      @JsonProperty    
      public void setPassword(String password) {
        this.password = password;
      }
    
      @JsonIgnore
      public String getPassword() {
        return this.password;
      }
    
    }
    

    setter 方法上的@JsonProperty 将用于序列化,而getter 方法上的JsonIgnore 将用于反序列化。

    【讨论】:

    • 谢谢,但在这种情况下,即使在应用程序“内部”,我也不会得到密码字段;我需要它在登录时验证用户。
    • 应用程序“内部”是什么意思。您可以直接在应用程序内使用对象。它将具有密码值。
    • 我直接在JS上存储对象。如果我添加 JsonIgnore 来获取;当我将对象映射到 JSON 时,我会在更新时丢失密码字段。
    【解决方案3】:

    实际上@Manikandan 的答案应该适合你。见Only using @JsonIgnore during serialization, but not deserialization

    在最坏的情况下,您可能会尝试实现 JsonSerializer。

    public class MyObjectSerializer extends JsonSerializer<MyObject> {
    
        @Override
        public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
            jgen.writeStartObject();
            jgen.writeString(value.getField1());
            jgen.writeString(value.getField2());
            /* and not include field that you don't want to serialize */
            jgen.writeEndObject();
        }
    
    }
    
    @JsonSerialize(using = MyObjectSerializer.class)
    public class MyObject {
    
        String field1;
        Integer field2;
        String fieldNotToBeSerialized;
    
        public String getField1() {
            return field1;
        }
        public void setField1(String field1) {
            this.field1 = field1;
        }
        public Integer getField2() {
            return field2;
        }
        public void setField2(Integer field2) {
            this.field2 = field2;
        }
        public String getFieldNotToBeSerialized() {
            return fieldNotToBeSerialized;
        }
        public void setFieldNotToBeSerialized(String fieldNotToBeSerialized) {
            this.fieldNotToBeSerialized = fieldNotToBeSerialized;
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-16
      • 2014-07-10
      相关资源
      最近更新 更多