如何为其他包中的Java类添加无参构造器?解决GeoJsonMultiPolygon无参构造缺失引发的Jackson反序列化异常
GeoJsonMultiPolygon with Jackson (No No-Arg Constructor) Got it, this is a classic Jackson deserialization problem when dealing with third-party classes that don't expose a no-arg constructor. Since you can't modify the org.springframework.data.mongodb.core.geo.GeoJsonMultiPolygon code, here are two reliable workarounds to get your deserialization working properly:
Option 1: Custom Jackson Deserializer
We can create a custom JsonDeserializer to manually parse the JSON structure and build the GeoJsonMultiPolygon object ourselves.
Step 1: Create the Custom Deserializer
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import org.springframework.data.mongodb.core.geo.GeoJsonMultiPolygon; import org.springframework.data.mongodb.core.geo.GeoJsonPolygon; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class GeoJsonMultiPolygonDeserializer extends JsonDeserializer<GeoJsonMultiPolygon> { @Override public GeoJsonMultiPolygon deserialize(JsonParser parser, DeserializationContext ctx) throws IOException { JsonNode rootNode = parser.getCodec().readTree(parser); JsonNode coordinatesNode = rootNode.get("coordinates"); List<GeoJsonPolygon> polygons = new ArrayList<>(); // Traverse each Polygon in the MultiPolygon for (JsonNode polygonNode : coordinatesNode) { List<List<GeoJsonPoint>> polygonCoords = new ArrayList<>(); // Traverse each ring (outer + inner rings) in the Polygon for (JsonNode ringNode : polygonNode) { List<GeoJsonPoint> ringPoints = new ArrayList<>(); // Parse each latitude/longitude point for (JsonNode pointNode : ringNode) { double longitude = pointNode.get(0).asDouble(); double latitude = pointNode.get(1).asDouble(); ringPoints.add(new GeoJsonPoint(longitude, latitude)); } polygonCoords.add(ringPoints); } polygons.add(new GeoJsonPolygon(polygonCoords)); } return new GeoJsonMultiPolygon(polygons); } }
Step 2: Attach the Deserializer to Your Model Field
Update your CountryBoundaries class to use the custom deserializer on the geometry field:
@Getter @Setter @ToString @EqualsAndHashCode @Builder @AllArgsConstructor @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @Document(collection = "country-boundaries") public class CountryBoundaries { @Id private String id; @EqualsAndHashCode.Exclude private String type; @EqualsAndHashCode.Exclude private CountryBoundariesProperties properties; @EqualsAndHashCode.Exclude @JsonDeserialize(using = GeoJsonMultiPolygonDeserializer.class) // Add this annotation private GeoJsonMultiPolygon geometry; }
Your existing deserialization code will now work as expected, since Jackson will use your custom logic to build the GeoJsonMultiPolygon instance.
Option 2: Use Spring Data MongoDB's Built-In Jackson Module
If you're already using Spring Data MongoDB in your project, you can leverage its pre-built MongoJackson2Module which handles serialization/deserialization for all Spring Data GeoJSON types out of the box.
Update Your Deserialization Code
Modify your ObjectMapper setup to register the module:
ObjectMapper mapper = new ObjectMapper(); // Register the MongoDB Jackson module to handle GeoJSON types mapper.registerModule(new MongoJackson2Module()); InputStream is = Country.class.getResourceAsStream("/country-boundaries.json"); List<CountryBoundaries> countryBoundaries = mapper.readValue(is, new TypeReference<>(){}); countryBoundariesRepository.saveAll(countryBoundaries);
Verify Dependency
Make sure your project includes the Spring Data MongoDB dependency (for Maven):
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>your-version-here</version> </dependency>
This is the cleaner option for Spring-based projects, as it eliminates the need for custom deserialization code.
内容的提问来源于stack exchange,提问作者daph111

