Spring Data继承字段引发MappingException:如何解决歧义映射?
Great question! Let's break down what's causing this issue and how to fix it properly while keeping your inheritance structure intact.
First, the root problem: You've redefined the myList field in your Foo subclass, which already exists in the parent Bar class. This creates two critical issues:
- Field hiding: The subclass field shadows the parent's field, which is a poor Java practice and leads to unexpected runtime behavior.
- Mapping ambiguity: Both Spring Data (for persistence) and Jackson (for JSON serialization) detect two separate fields with the exact same name, triggering the
MappingExceptionyou're seeing.
Your core need is clear: When serializing a Foo instance, myList shouldn't be sent over the network (but it should still be accepted during deserialization, matching the WRITE_ONLY behavior). Here's how to achieve this without redefining the field in the subclass:
Step 1: Remove the duplicate field from Foo
Delete the myList field definition from Foo entirely. Thanks to inheritance, Foo already has full access to the parent Bar's myList field—there's no need to redefine it.
Step 2: Control serialization behavior in the subclass
To get the WRITE_ONLY effect for Foo, override the getter method for myList (add standard getters/setters to Bar if you don't have them already) and annotate it with @JsonIgnore. This tells Jackson to skip serializing the field, while leaving the setter intact to handle deserialization.
Updated Code Example:
public class Bar { public List<X> myList; // Add getter and setter if missing (required for Jackson to access the field) public List<X> getMyList() { return myList; } public void setMyList(List<X> myList) { this.myList = myList; } public void methodsThatAccessMyList() { // Existing methods that use myList—no changes needed here // No code duplication since all subclasses inherit these methods } } public class Foo extends Bar { @Override @JsonIgnore // Prevents myList from being included in JSON responses for Foo instances public List<X> getMyList() { return super.getMyList(); } // Keep the setter unannotated to allow Jackson to deserialize myList from requests @Override public void setMyList(List<X> myList) { super.setMyList(myList); } }
Alternative: Use Jackson Mix-ins (if you can't modify subclass methods)
If you can't add or override methods in Foo, you can use Jackson's mix-in annotations to apply the WRITE_ONLY behavior without changing the subclass code directly:
- Create a mix-in class:
abstract class FooMyListMixIn { @JsonProperty(access = Access.WRITE_ONLY) private List<X> myList; }
- Register the mix-in with your ObjectMapper (in Spring Boot, configure this via a
@Configurationclass):
@Configuration public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilder objectMapperBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.mixIn(Foo.class, FooMyListMixIn.class); return builder; } }
Why this works:
- Removing the duplicate field eliminates the Spring Data mapping ambiguity entirely—there's now only one
myListfield to map to your persistence layer. - The
@JsonIgnoreon the subclass getter ensuresmyListisn't sent over the network forFooinstances, while the unannotated setter lets Jackson still accept the field from incoming requests—exactly matching theWRITE_ONLYbehavior you wanted.
内容的提问来源于stack exchange,提问作者Codehai

