Skip to content

Commit

Permalink
Merge pull request #75 from nicmunroe/bugfix/enable-error-contract-ob…
Browse files Browse the repository at this point in the history
…ject-mapper-customization

Fix the jackson error contract serializer so it can be further modified e.g. with custom serializers
  • Loading branch information
nicmunroe authored Sep 15, 2024
2 parents a217168 + de0b909 commit 84be270
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
import com.fasterxml.jackson.databind.ser.SerializerFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -94,6 +95,15 @@ protected ErrorContractSerializationFactory(SerializerFactoryConfig config,
this.serializeErrorCodeFieldAsIntegerIfPossible = serializeErrorCodeFieldAsIntegerIfPossible;
}

@Override
public SerializerFactory withConfig(SerializerFactoryConfig config) {
return new ErrorContractSerializationFactory(
config,
excludeEmptyMetadataFromJson,
serializeErrorCodeFieldAsIntegerIfPossible
);
}

@Override
protected List<BeanPropertyWriter> filterBeanProperties(SerializationConfig config, BeanDescription beanDesc,
List<BeanPropertyWriter> props) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
import com.nike.internal.util.testing.Glassbox;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;

Expand All @@ -22,6 +25,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

Expand Down Expand Up @@ -317,4 +321,66 @@ public static class FooClass {
public String code = "42";
}

// Essentially a duplicate of DefaultErrorContractDTO, but with the error ID named `someAltErrorIdForContract` instead of `error_id`.
private record AlternateErrorContract(String someAltErrorIdForContract, List<DefaultErrorDTO> errors) {
}

private static class AltErrorContractSerializer extends StdSerializer<DefaultErrorContractDTO> {
public AltErrorContractSerializer() {
super(DefaultErrorContractDTO.class);
}

@Override
public void serialize(DefaultErrorContractDTO value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
AlternateErrorContract altContract = new AlternateErrorContract(value.error_id, value.errors);
provider.defaultSerializeValue(altContract, gen);
}
}

@Test
public void withConfig_override_works_as_expected() throws JsonProcessingException {
// given
boolean excludeEmptyMetadataFromJson = true;
boolean serializeErrorCodeFieldAsIntegerIfPossible = true;
ObjectMapper mapper = new ObjectMapper().setSerializerFactory(
new ErrorContractSerializationFactory(
null,
excludeEmptyMetadataFromJson,
serializeErrorCodeFieldAsIntegerIfPossible
));

SimpleModule module = new SimpleModule();
module.addSerializer(DefaultErrorContractDTO.class, new AltErrorContractSerializer());

Map<String, Object> origContract43Metadata = Map.of("metafoo", "metabar", "meta42", 43);
DefaultErrorContractDTO origContract = new DefaultErrorContractDTO(UUID.randomUUID().toString(), Arrays.asList(
new DefaultErrorDTO(42, "foo", null),
new DefaultErrorDTO("43", "bar", origContract43Metadata)
), null);

// when
Throwable ex = catchThrowable(() -> mapper.registerModule(module));

// then
assertThat(ex).isNull();

// and when
String resultJsonStr = JsonUtilWithDefaultErrorContractDTOSupport.writeValueAsString(origContract, mapper);
@SuppressWarnings("unchecked")
Map<String, Object> resultJsonMap = objectMapper.readValue(resultJsonStr, Map.class);

// then
// Note that the error_id field is renamed to someAltErrorIdForContract, the metadata is missing entirely from
// the first error, and and string code "43" was converted to an int. Therefore we know both the original
// error contract serializer is working, and the additional AltErrorContractSerializer is also working.
assertThat(resultJsonMap).isEqualTo(Map.of(
"someAltErrorIdForContract", origContract.error_id,
"errors", Arrays.asList(
Map.of("code", 42, "message", "foo"),
Map.of("code", 43, "message", "bar", "metadata", origContract43Metadata)
)
));
}

}

0 comments on commit 84be270

Please sign in to comment.