From c8eb0cd46859592510f8af27297d97d1dcd8c67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 27 Aug 2021 10:24:19 +0200 Subject: [PATCH] Reproduce `no default no-arg ctor found` regression in XmlMapper. --- .../XmlMapperNoArgCtorRegressionTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/failing/XmlMapperNoArgCtorRegressionTest.java diff --git a/src/test/java/com/fasterxml/jackson/failing/XmlMapperNoArgCtorRegressionTest.java b/src/test/java/com/fasterxml/jackson/failing/XmlMapperNoArgCtorRegressionTest.java new file mode 100644 index 0000000..3473673 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/failing/XmlMapperNoArgCtorRegressionTest.java @@ -0,0 +1,141 @@ +package com.fasterxml.jackson.failing; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRootName; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.integtest.BaseTest; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * Reproduces no default no-arg ctor found regression introduced to {@link XmlMapper} in 2.12.0. + * + * @see jackson-dataformat-xml issue 491 + */ +public class XmlMapperNoArgCtorRegressionTest extends BaseTest { + + interface Problem { + + String DEFAULT_TYPE = "about:blank"; + + int DEFAULT_STATUS = 500; + + String getType(); + + int getStatus(); + + } + + static class DefaultProblem implements Problem { + + private final String type; + + private final int status; + + /** + * This is required to workaround Jackson's missing support for static + * {@link JsonCreator}s in mix-ins. That is, we need to define the + * creator on a constructor in the mix-in that is matching with a + * constructor here too. + * + * @see jackson-databind issue 1820 + */ + DefaultProblem(String type, Integer status) { + this.type = type != null ? type : Problem.DEFAULT_TYPE; + this.status = status != null ? status : Problem.DEFAULT_STATUS; + } + + @Override + public String getType() { + return type; + } + + @Override + public int getStatus() { + return status; + } + + } + + @JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXISTING_PROPERTY, + property = "type", + defaultImpl = DefaultProblem.class, + visible = true) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @JsonRootName("problem") + interface ProblemMixIn extends Problem { + + @Override + @JsonProperty("type") + String getType(); + + @Override + @JsonProperty("status") + int getStatus(); + + } + + abstract static class DefaultProblemMixIn extends DefaultProblem { + + @JsonCreator + DefaultProblemMixIn( + @JsonProperty("type") String type, + @JsonProperty("status") Integer status) { + super(type, status); + throw new IllegalStateException( + "mix-in constructor is there only for extracting the JSON mapping, " + + "it should not have been called"); + } + + } + + static class ProblemModule extends SimpleModule { + + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + registerMixIns(context); + } + + private static void registerMixIns(SetupContext context) { + context.setMixInAnnotations(DefaultProblem.class, DefaultProblemMixIn.class); + context.setMixInAnnotations(Problem.class, ProblemMixIn.class); + } + + } + + private static final ProblemModule MODULE = new ProblemModule(); + + private static final ObjectMapper JSON_MAPPER = new ObjectMapper().registerModule(MODULE); + + private static final XmlMapper XML_MAPPER = (XmlMapper) new XmlMapper().registerModule(MODULE); + + /** + * Passes on 2.11.4 and 2.12.{0..4}. + */ + public void test_empty_Problem_JSON_deserialization() throws IOException { + byte[] problemJsonBytes = "{}".getBytes(StandardCharsets.UTF_8); + Problem problem = JSON_MAPPER.readValue(problemJsonBytes, Problem.class); + assertEquals(Problem.DEFAULT_TYPE, problem.getType()); + assertEquals(Problem.DEFAULT_STATUS, problem.getStatus()); + } + + /** + * Passes on 2.11.4, but fails on 2.12.{0..4}. + */ + public void test_empty_Problem_XML_deserialization() throws IOException { + byte[] problemXmlBytes = "".getBytes(StandardCharsets.UTF_8); + Problem problem = XML_MAPPER.readValue(problemXmlBytes, Problem.class); + assertEquals(Problem.DEFAULT_TYPE, problem.getType()); + assertEquals(Problem.DEFAULT_STATUS, problem.getStatus()); + } + +}