|
26 | 26 | import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder;
|
27 | 27 | import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
|
28 | 28 |
|
| 29 | +import java.lang.reflect.Member; |
29 | 30 | import java.util.List;
|
30 | 31 | import java.util.stream.Collectors;
|
31 | 32 |
|
@@ -64,23 +65,40 @@ public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanD
|
64 | 65 | }
|
65 | 66 | });
|
66 | 67 | setSerializerModifier(new BeanSerializerModifier() {
|
| 68 | + /** |
| 69 | + * Customizes property writers used during serialization. |
| 70 | + * |
| 71 | + * This method wraps standard property writers in a delegate that can suppress serialization |
| 72 | + * of fields that may be overridden by values in the map returned by {@code @JsonAnyGetter}. |
| 73 | + * |
| 74 | + * The property corresponding to the {@code @JsonAnyGetter} method itself is left unmodified |
| 75 | + * to avoid interfering with Jackson’s internal handling via {@link com.fasterxml.jackson.databind.ser.AnyGetterWriter}. |
| 76 | + * |
| 77 | + * This mechanism ensures that if a field is both explicitly declared and also present in the |
| 78 | + * any-getter map, only the value from the any-getter is serialized, avoiding duplication or conflicts. |
| 79 | + */ |
67 | 80 | @Override
|
68 | 81 | public BeanSerializerBuilder updateBuilder(SerializationConfig config, BeanDescription beanDesc,
|
69 | 82 | BeanSerializerBuilder builder) {
|
70 | 83 | AnnotatedMember anyGetter = beanDesc.findAnyGetter();
|
| 84 | + Member anyGetterMember = (anyGetter != null) ? anyGetter.getMember() : null; |
71 | 85 |
|
72 |
| - List<BeanPropertyWriter> originalWriters = builder.getProperties(); |
73 |
| - |
74 |
| - List<BeanPropertyWriter> newWriters = originalWriters.stream() |
| 86 | + // Wrap each property writer unless it's the any-getter (handled by Jackson separately) |
| 87 | + List<BeanPropertyWriter> customWriters = builder.getProperties().stream() |
75 | 88 | .map(writer -> {
|
76 |
| - if ("additionalProperties".equals(writer.getName())) { |
| 89 | + if (isAnyGetterWriter(writer, anyGetterMember)) { |
| 90 | + // Skipping wrapping for any-getter to avoid interfering with Jackson's internal handling |
77 | 91 | return writer;
|
78 | 92 | }
|
79 |
| - return new BeanPropertyWriterDelegate(writer, anyGetter, UnmatchedFieldTypeModule.this::isLogWarnings); |
| 93 | + // Wrap normal field writers with delegate to handle overrides and logging |
| 94 | + return new BeanPropertyWriterDelegate( |
| 95 | + writer, |
| 96 | + anyGetter, |
| 97 | + UnmatchedFieldTypeModule.this::isLogWarnings); |
80 | 98 | })
|
81 | 99 | .collect(Collectors.toList());
|
82 | 100 |
|
83 |
| - builder.setProperties(newWriters); |
| 101 | + builder.setProperties(customWriters); |
84 | 102 | return builder;
|
85 | 103 | }
|
86 | 104 | });
|
@@ -128,4 +146,22 @@ public static void removeInTemplate() {
|
128 | 146 | IN_TEMPLATE.remove();
|
129 | 147 | }
|
130 | 148 |
|
| 149 | + /** |
| 150 | + * Checks whether the given {@link BeanPropertyWriter} corresponds to the method annotated with {@code @JsonAnyGetter}. |
| 151 | + * |
| 152 | + * This is used to identify and exclude the any-getter property from custom wrapping, |
| 153 | + * since Jackson handles it separately via {@link com.fasterxml.jackson.databind.ser.AnyGetterWriter}. |
| 154 | + * |
| 155 | + * @param writer the property writer to examine |
| 156 | + * @param anyGetterMember the reflective member (method or field) marked with {@code @JsonAnyGetter}, if available |
| 157 | + * @return {@code true} if the writer represents the any-getter property; {@code false} otherwise |
| 158 | + */ |
| 159 | + private boolean isAnyGetterWriter(BeanPropertyWriter writer, Member anyGetterMember) { |
| 160 | + if (writer == null || anyGetterMember == null) { |
| 161 | + return false; |
| 162 | + } |
| 163 | + AnnotatedMember annotated = writer.getMember(); |
| 164 | + Member member = (annotated != null) ? annotated.getMember() : null; |
| 165 | + return member != null && member.equals(anyGetterMember); |
| 166 | + } |
131 | 167 | }
|
0 commit comments