diff --git a/README.md b/README.md index f895df9..b17453f 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,16 @@ public final class OutOfStockProblem implements Problem { Jackson is now able to deserialize specific problems into their respective types. By default, e.g. if a type is not associated with a class, it will fall back to a `DefaultProblem`. +When deserializing directly into a concrete custom subtype of +`AbstractThrowableProblem`, disable polymorphic type resolution on that subtype: + +```java +@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +public final class OutOfStockProblem extends AbstractThrowableProblem { + // ... +} +``` + ### Catching problems If you read about [Throwing problems](#throwing-problems) already, you should be familiar with `ThrowableProblem`. diff --git a/problem-jackson2/src/test/java/org/zalando/problem/jackson/ProblemMixInTest.java b/problem-jackson2/src/test/java/org/zalando/problem/jackson/ProblemMixInTest.java index db07df0..f168867 100644 --- a/problem-jackson2/src/test/java/org/zalando/problem/jackson/ProblemMixInTest.java +++ b/problem-jackson2/src/test/java/org/zalando/problem/jackson/ProblemMixInTest.java @@ -43,6 +43,23 @@ final class ProblemMixInTest { mapper.registerSubtypes(OutOfStockException.class); } + @Test + void shouldDeserializeConcreteThrowableProblemSubtype() throws Exception { + final ResourceNotFoundProblem original = + new ResourceNotFoundProblem("123", "Resource not found"); + + final String json = mapper.writeValueAsString(original); + + final ResourceNotFoundProblem deserialized = + mapper.readValue(json, ResourceNotFoundProblem.class); + + assertThat(deserialized.getType(), equalTo(original.getType())); + assertThat(deserialized.getTitle(), equalTo(original.getTitle())); + assertThat(deserialized.getStatus(), equalTo(original.getStatus())); + assertThat(deserialized.getDetail(), equalTo(original.getDetail())); + assertThat(deserialized.getId(), equalTo(original.getId())); + } + @Test void shouldSerializeDefaultProblem() throws JsonProcessingException { final Problem problem = Problem.valueOf(Status.NOT_FOUND); diff --git a/problem-jackson2/src/test/java/org/zalando/problem/jackson/ResourceNotFoundProblem.java b/problem-jackson2/src/test/java/org/zalando/problem/jackson/ResourceNotFoundProblem.java new file mode 100644 index 0000000..7a9a20b --- /dev/null +++ b/problem-jackson2/src/test/java/org/zalando/problem/jackson/ResourceNotFoundProblem.java @@ -0,0 +1,33 @@ +package org.zalando.problem.jackson; + +import java.net.URI; + +import org.zalando.problem.AbstractThrowableProblem; +import org.zalando.problem.Status; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +public final class ResourceNotFoundProblem extends AbstractThrowableProblem { + + private static final URI TYPE = URI.create( + "https://your-company.com/problems/ResourceNotFoundProblem.html" + ); + + private final String id; + + @JsonCreator + public ResourceNotFoundProblem( + @JsonProperty("id") final String id, + @JsonProperty("detail") final String detail + ) { + super(TYPE, "Resource not found", Status.NOT_FOUND, detail); + this.id = id; + } + + public String getId() { + return id; + } +}