From 998324e8cc1a5f8dd17a34a4959eb68ae208888f Mon Sep 17 00:00:00 2001 From: Igor Murzich Date: Wed, 8 Oct 2025 19:43:32 +0300 Subject: [PATCH] New annotation JacksonXmlInclude works like JsonInclue but for xml. --- .../xml/JacksonXmlAnnotationIntrospector.java | 23 ++++++ .../xml/annotation/JacksonXmlInclude.java | 29 ++++++++ .../xml/ser/TestSerializationInclude.java | 71 +++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 src/main/java/com/fasterxml/jackson/dataformat/xml/annotation/JacksonXmlInclude.java create mode 100644 src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestSerializationInclude.java diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/JacksonXmlAnnotationIntrospector.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/JacksonXmlAnnotationIntrospector.java index ee61709d0..eb6473caf 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/JacksonXmlAnnotationIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/JacksonXmlAnnotationIntrospector.java @@ -3,6 +3,7 @@ import java.lang.annotation.Annotation; import java.util.List; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.databind.JavaType; @@ -220,6 +221,28 @@ public PropertyName findNameForDeserialization(Annotated a) return pn; } + /* + /********************************************************************** + /* Overrides for JsonInclude, property detection + /********************************************************************** + */ + + @Override + public JsonInclude.Value findPropertyInclusion(Annotated a) + { + JacksonXmlInclude xmlInclude = _findAnnotation(a, JacksonXmlInclude.class); + if (xmlInclude != null) { + return JsonInclude.Value.construct( + JsonInclude.Include.valueOf(xmlInclude.value().name()), + JsonInclude.Include.valueOf(xmlInclude.content().name()), + xmlInclude.valueFilter(), + xmlInclude.contentFilter() + ); + } else { + return JsonInclude.Value.empty(); + } + } + /* /********************************************************************** /* Overrides for non-public helper methods diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/annotation/JacksonXmlInclude.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/annotation/JacksonXmlInclude.java new file mode 100644 index 000000000..61808328c --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/annotation/JacksonXmlInclude.java @@ -0,0 +1,29 @@ +package com.fasterxml.jackson.dataformat.xml.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that can be used to provide XML-specific configuration + * for include properties like {@code @JsonInclude} for json. + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, + ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JacksonXmlInclude { + Include value() default Include.ALWAYS; + Include content() default Include.ALWAYS; + Class valueFilter() default Void.class; + Class contentFilter() default Void.class; + + public enum Include { + ALWAYS, + NON_NULL, + NON_ABSENT, + NON_EMPTY, + NON_DEFAULT, + CUSTOM + } +} \ No newline at end of file diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestSerializationInclude.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestSerializationInclude.java new file mode 100644 index 000000000..c67cddec5 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/ser/TestSerializationInclude.java @@ -0,0 +1,71 @@ +package com.fasterxml.jackson.dataformat.xml.ser; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.XmlTestBase; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlInclude; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlInclude.Include; + +public class TestSerializationInclude extends XmlTestBase +{ + @JacksonXmlInclude(value = Include.NON_EMPTY) + static class NonEmptyClassBean { + public String a; + public String b; + public String c; + + public NonEmptyClassBean(String a, String b, String c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + static class NonEmptyPropertyBean { + public String a; + public String b; + @JacksonXmlInclude(value = Include.NON_EMPTY) + public String c; + + public NonEmptyPropertyBean(String a, String b, String c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + @JacksonXmlInclude(value = Include.NON_EMPTY) + static class MergeBean { + public String a; + @JacksonXmlInclude(value = Include.NON_NULL) + public String b; + public String c; + + public MergeBean(String a, String b, String c) { + this.a = a; + this.b = b; + this.c = c; + } + } + + + private final XmlMapper MAPPER = newMapper(); + + public void testNonEmptyClass() throws Exception + { + String xml = MAPPER.writeValueAsString(new NonEmptyClassBean("1", "", "3")); + assertEquals("13", xml); + } + + public void testNonEmptyProperty() throws Exception + { + String xml = MAPPER.writeValueAsString(new NonEmptyPropertyBean("1", "", "")); + assertEquals("1", xml); + } + + public void testMerge() throws Exception + { + String xml = MAPPER.writeValueAsString(new MergeBean("1", "", "3")); + assertEquals("13", xml); + } + +} \ No newline at end of file