如何让Jackson在CSV序列化时跳过解包子POJO的指定字段列
如何让Jackson序列化CSV时跳过已解包子POJO的指定列(无法修改子POJO类)
我来帮你搞定这个问题!你遇到的情况是:用@JsonUnwrapped展开Bar类的字段后,@JsonIgnoreProperties只能忽略字段的值,但CSV里还是会生成bar.toBeIgnored这一列(值为空),而且你还没办法修改Bar类的代码。下面给你两种可行的解决方案:
方案1:使用Jackson Mixin(推荐)
Jackson的Mixin机制允许我们在不修改原类的前提下,给它添加Jackson注解规则。我们可以通过Mixin给Bar的toBeIgnored字段加上@JsonIgnore,这样Jackson在生成CSV Schema时就会完全忽略这个字段,连列都不会生成。
具体步骤:
- 先创建一个
Bar的Mixin类,给目标字段标注@JsonIgnore:
abstract class BarMixin { @JsonIgnore String toBeIgnored; }
- 在你的测试代码里,给
CsvMapper注册这个Mixin,告诉Jackson用它来处理Bar类:
CsvMapper mapper = new CsvMapper(); mapper.addMixIn(Bar.class, BarMixin.class);
- 剩下的代码保持不变就好,此时序列化后的CSV就不会出现
bar.toBeIgnored列了。
方案2:手动修改CsvSchema
如果你不想用Mixin,也可以直接在生成CSV Schema后,手动移除不需要的列:
CsvMapper mapper = new CsvMapper(); CsvSchema schema = mapper.schemaFor(Foo.class).withHeader(); // 从Schema中移除指定列 schema = schema.rebuild().removeColumn("bar.toBeIgnored").build(); ObjectWriter csvWriter = mapper.writer(schema);
这种方法直接操作Schema对象,把不需要的列删掉,同样能达到跳过整列的效果。
为什么原来的@JsonIgnoreProperties没用?
简单说,@JsonIgnoreProperties({"toBeIgnored"})只会告诉Jackson不要序列化这个字段的值,但Jackson在生成CSV Schema的时候,还是会通过反射读取Bar类的所有字段信息,所以对应的列依然会被创建,只是值为空。而上面的两种方法,要么通过Mixin让Jackson彻底忽略这个字段(Schema生成阶段就不会包含它),要么直接从Schema中移除列,从根源上解决了问题。
修改后的完整测试代码(Mixin版本)
public class FooTest { class Foo { String something = "value"; @JsonUnwrapped(prefix = "bar.") Bar bar; public String getSomething() { return something; } public Bar getBar() { return bar; } } class Bar { String toBeIgnored; public String getToBeIgnored() { return toBeIgnored; } } // Bar类的Mixin abstract class BarMixin { @JsonIgnore String toBeIgnored; } @Test public void fooTest() throws IOException { CsvMapper mapper = new CsvMapper(); // 注册Mixin mapper.addMixIn(Bar.class, BarMixin.class); CsvSchema schema = mapper.schemaFor(Foo.class).withHeader(); ObjectWriter csvWriter = mapper.writer(schema); OutputStream outputStream = new ByteArrayOutputStream(); SequenceWriter writer = csvWriter.writeValues(outputStream); Foo foo = new Foo(); foo.bar = new Bar(); String toBeIgnored = "should not be parsed"; foo.bar.toBeIgnored = toBeIgnored; writer.write(foo); String result = outputStream.toString(); assertThat(result).doesNotContain(toBeIgnored); assertThat(result).contains("something"); assertThat(result).doesNotContain("bar.toBeIgnored"); } }
内容的提问来源于stack exchange,提问作者Jeep87c
相关产品推荐
相关产品推荐

