Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #26 from CJSCommonPlatform/fix-integer-enum
Browse files Browse the repository at this point in the history
Add Integer based enum capability for serialisation and deserialization of Json
  • Loading branch information
Allan Mckenzie committed Jul 26, 2018
2 parents fb8d3d6 + 7632256 commit 993482a
Show file tree
Hide file tree
Showing 13 changed files with 553 additions and 23 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to

## [Unreleased]

### Changed
- Add Integer based enum capability for serialisation and deserialization of Json

## [1.14.0] - 2018-07-20

### Changed
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<properties>
<cpp.repo.name>utilities</cpp.repo.name>
<common-bom.version>1.27.0</common-bom.version>
<common-bom.version>1.28.0</common-bom.version>
<test-utils.version>1.17.3</test-utils.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static uk.gov.justice.services.common.converter.ZonedDateTimes.ISO_8601;

import uk.gov.justice.services.common.converter.jackson.additionalproperties.AdditionalPropertiesModule;
import uk.gov.justice.services.common.converter.jackson.integerenum.IntegerEnumModule;
import uk.gov.justice.services.common.converter.jackson.jsr353.InclusionAwareJSR353Module;

import java.time.ZonedDateTime;
Expand Down Expand Up @@ -50,6 +51,7 @@ private ObjectMapper configureObjectMapper(final ObjectMapper objectMapper) {
.registerModule(new ParameterNamesModule(PROPERTIES))
.registerModule(new InclusionAwareJSR353Module())
.registerModule(new AdditionalPropertiesModule())
.registerModule(new IntegerEnumModule())
.configure(WRITE_DATES_AS_TIMESTAMPS, false)
.configure(WRITE_DATES_WITH_ZONE_ID, false)
.configure(WRITE_NULL_MAP_VALUES, false)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package uk.gov.justice.services.common.converter.jackson.integerenum;

import static java.util.Optional.empty;
import static java.util.Optional.of;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Optional;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.SerializerProvider;

public class EnumObjectUtil implements Serializable {

private static final long serialVersionUID = -7399009049859936180L;

public Optional<Object> findEnumObject(final Object enumObject, final int enumValue) {
final Field[] declaredFields = enumObject.getClass().getDeclaredFields();

for (final Field field : declaredFields) {
if (isIntegerFieldType(field)) {
try {
field.setAccessible(true);
final int fieldValue = (int) field.get(enumObject);
if (fieldValue == enumValue) {
return of(enumObject);
}
} catch (final IllegalAccessException e) {
//Do nothing
}
}
}
return empty();
}

public Optional<Integer> integerValueFromFieldOfEnum(final Enum<?> enumObject,
final String fieldName,
final SerializerProvider serializerProvider) throws JsonMappingException {
try {
final Field field = enumObject.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return Optional.of((Integer) field.get(enumObject));
} catch (NoSuchFieldException | IllegalAccessException ex) {
throw serializerProvider.mappingException("Could not serialize enum object", ex);
}
}

public Optional<String> integerFieldNameFrom(final Enum<?> enumObject) {
final Field[] fields = enumObject.getClass().getDeclaredFields();

for (final Field field : fields) {
if (isIntegerFieldType(field)) {
return Optional.of(field.getName());
}
}

return empty();
}

private boolean isIntegerFieldType(final Field field) {
return Integer.class.isAssignableFrom(field.getType());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package uk.gov.justice.services.common.converter.jackson.integerenum;

import static com.fasterxml.jackson.databind.AnnotationIntrospector.nopInstance;
import static com.fasterxml.jackson.databind.util.EnumResolver.constructFor;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.util.EnumResolver;

public class IntegerEnumBeanDeserializerModifier extends BeanDeserializerModifier {

@SuppressWarnings("unchecked")
@Override
public JsonDeserializer<?> modifyEnumDeserializer(
final DeserializationConfig config,
final JavaType type,
final BeanDescription beanDesc,
final JsonDeserializer<?> deserializer) {

final Class<Enum<?>> enumClass = (Class<Enum<?>>) type.getRawClass();

final EnumResolver enumResolver = constructFor(enumClass, nopInstance());

return new IntegerEnumDeserializer(
enumResolver,
new EnumObjectUtil());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package uk.gov.justice.services.common.converter.jackson.integerenum;

import static java.util.Arrays.stream;

import java.lang.reflect.Field;
import java.util.Optional;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.ser.std.EnumSerializer;
import com.fasterxml.jackson.databind.util.EnumValues;


public class IntegerEnumBeanSerializerModifier extends BeanSerializerModifier {

@Override
public JsonSerializer<?> modifyEnumSerializer(final SerializationConfig config,
final JavaType valueType,
final BeanDescription beanDesc,
final JsonSerializer<?> serializer) {

final EnumValues enumValues = ((EnumSerializer) serializer).getEnumValues();
final Optional integerEnum = isIntegerEnum(enumValues);

if (integerEnum.isPresent()) {
return new IntegerEnumSerializer(
enumValues.getEnumClass(),
new EnumObjectUtil());
}
return super.modifySerializer(config, beanDesc, serializer);
}

private Optional isIntegerEnum(final EnumValues enumValues) {
final Class<Enum<?>> enumClass = enumValues.getEnumClass();

final Field[] declaredFields = enumClass.getDeclaredFields();

return stream(declaredFields)
.filter(field -> Integer.class.isAssignableFrom(field.getType()))
.findFirst();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package uk.gov.justice.services.common.converter.jackson.integerenum;

import static java.util.Arrays.asList;

import java.io.IOException;
import java.util.List;
import java.util.Optional;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.EnumDeserializer;
import com.fasterxml.jackson.databind.util.EnumResolver;

public class IntegerEnumDeserializer extends EnumDeserializer {

private static final long serialVersionUID = 1L;

private final List<Enum<?>> enumerations;
private final EnumObjectUtil enumObjectUtil;

public IntegerEnumDeserializer(final EnumResolver enumResolver,
final EnumObjectUtil enumObjectUtil) {
super(enumResolver);
this.enumerations = asList(enumResolver.getRawEnums());
this.enumObjectUtil = enumObjectUtil;
}

@Override
public Object deserialize(final JsonParser jsonParser, final DeserializationContext context) throws IOException {

if (jsonParser.getCurrentToken() == JsonToken.VALUE_NUMBER_INT) {

final int enumValue = jsonParser.getIntValue();

for (final Object enumObject : enumerations) {

final Optional<Object> enumerationFound = enumObjectUtil.findEnumObject(enumObject, enumValue);

if (enumerationFound.isPresent()) {
return enumerationFound.get();
}
}
}

return super.deserialize(jsonParser, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package uk.gov.justice.services.common.converter.jackson.integerenum;

import com.fasterxml.jackson.databind.module.SimpleModule;

public class IntegerEnumModule extends SimpleModule {

@Override
public void setupModule(final SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new IntegerEnumBeanSerializerModifier());
context.addBeanDeserializerModifier(new IntegerEnumBeanDeserializerModifier());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package uk.gov.justice.services.common.converter.jackson.integerenum;

import static java.util.Optional.empty;

import java.io.IOException;
import java.util.Optional;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;

public class IntegerEnumSerializer extends StdScalarSerializer<Enum<?>> {

private static final long serialVersionUID = 1L;

private final EnumObjectUtil enumObjectUtil;

public IntegerEnumSerializer(final Class<?> enumClass, final EnumObjectUtil enumObjectUtil) {
super(enumClass, false);
this.enumObjectUtil = enumObjectUtil;
}

@Override
public void serialize(final Enum<?> enumeration, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
final Optional<Integer> enumValue = getIntegerValue(enumeration, serializerProvider);

if (enumValue.isPresent()) {
jsonGenerator.writeNumber(enumValue.get());
}
}

private Optional<Integer> getIntegerValue(final Enum<?> enumObject, final SerializerProvider serializerProvider) throws IOException {
final Optional<String> fieldName = enumObjectUtil.integerFieldNameFrom(enumObject);

if (fieldName.isPresent()) {
return enumObjectUtil.integerValueFromFieldOfEnum(enumObject, fieldName.get(), serializerProvider);
}

return empty();
}
}

Loading

0 comments on commit 993482a

Please sign in to comment.