Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RosettaImmutables/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hubspot.rosetta.immutables;

import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

Expand All @@ -21,10 +22,11 @@ public static <T> T createContextual(Supplier<JavaType> typeSupplier,
Function<Class<?>, T> contextualFactory,
ExceptionHandler exceptionHandler) throws JsonMappingException {
JavaType contextualType = typeSupplier.get();
if (contextualType == null || !contextualType.hasRawClass(WireSafeEnum.class)) {
JavaType wireSafeType = findWireSafeTypeParameter(contextualType);
if (wireSafeType == null) {
exceptionHandler.report("Can not handle contextualType: " + contextualType);
} else {
JavaType[] typeParameters = contextualType.findTypeParameters(WireSafeEnum.class);
JavaType[] typeParameters = wireSafeType.findTypeParameters(WireSafeEnum.class);
if (typeParameters.length != 1) {
exceptionHandler.report("Can not discover enum type for: " + contextualType);
} else if (!typeParameters[0].isEnumType()) {
Expand All @@ -36,4 +38,20 @@ public static <T> T createContextual(Supplier<JavaType> typeSupplier,

return null;
}

private static JavaType findWireSafeTypeParameter(JavaType type) {
// Contextualization of the (de)serializers happens in this case without scoping to the specific type
// that we're being asked to handle, which means that the java type under inspection here is
// the full type of the bean property, which could in theory contain a WireSafeEnum anywhere,
// however in practice this is unlikely so we can get away with some specializations
if (type == null) {
return null;
} else if (type.hasRawClass(WireSafeEnum.class)) {
return type;
} else if (type.hasRawClass(Optional.class) || type.hasRawClass(com.google.common.base.Optional.class)) {
return type.containedType(0);
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.junit.Test;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.hubspot.immutables.utils.WireSafeEnum;
import com.hubspot.rosetta.Rosetta;
import com.hubspot.rosetta.immutables.beans.CustomEnum;
Expand All @@ -16,24 +19,47 @@ public class WireSafeEnumTest {
private static final ObjectMapper MAPPER = Rosetta
.getMapper()
.copy()
.registerModule(new RosettaImmutablesModule());
.registerModules(new RosettaImmutablesModule(), new Jdk8Module());

@Test
public void itCanSerializeBeanWithWireSafeField() {
WireSafeBean bean = new WireSafeBean();
bean.setSimple(WireSafeEnum.of(SimpleEnum.ONE));
bean.setCustom(WireSafeEnum.of(CustomEnum.ONE));
bean.setSimpleMaybe(Optional.of(WireSafeEnum.of(SimpleEnum.TWO)));
bean.setCustomMaybe(Optional.of(WireSafeEnum.of(CustomEnum.TWO)));

assertThat(serialize(bean)).isEqualTo(asNode("{\"simple\": \"ONE\", \"custom\": 1}"));
assertThat(serialize(bean)).isEqualTo(asNode("{\"simple\": \"ONE\", \"custom\": 1, \"simpleMaybe\": \"TWO\", \"customMaybe\": 2}"));
}

@Test
public void itCanDeserializeBeanWithWireSafeField() {
WireSafeBean bean = new WireSafeBean();
bean.setSimple(WireSafeEnum.of(SimpleEnum.ONE));
bean.setSimpleMaybe(Optional.of(WireSafeEnum.of(SimpleEnum.TWO)));
bean.setCustom(WireSafeEnum.of(CustomEnum.TWO));
bean.setCustomMaybe(Optional.of(WireSafeEnum.of(CustomEnum.ONE)));

assertThat(deserialize("{\"simple\": \"ONE\", \"simpleMaybe\": \"TWO\", \"custom\": 2, \"customMaybe\": 1}", WireSafeBean.class)).isEqualTo(bean);
}

@Test
public void itCanSerializeOptionalEmptyWireSafeFields() {
WireSafeBean bean = new WireSafeBean();
bean.setSimple(WireSafeEnum.of(SimpleEnum.ONE));
bean.setCustom(WireSafeEnum.of(CustomEnum.ONE));

assertThat(serialize(bean)).isEqualTo(asNode("{\"simple\": \"ONE\", \"custom\": 1, \"simpleMaybe\": null, \"customMaybe\": null}"));
}

@Test
public void itCanDeserializeBeanWithEmptyWireSafeField() {
WireSafeBean bean = new WireSafeBean();
bean.setSimple(WireSafeEnum.of(SimpleEnum.ONE));
bean.setSimpleMaybe(Optional.empty());
bean.setCustom(WireSafeEnum.of(CustomEnum.TWO));

assertThat(deserialize("{\"simple\": \"ONE\", \"custom\": 2}", WireSafeBean.class)).isEqualTo(bean);
assertThat(deserialize("{\"simple\": \"ONE\", \"simpleMaybe\": null, \"custom\": 2 }", WireSafeBean.class)).isEqualTo(bean);
}

private JsonNode asNode(String value) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,58 @@
package com.hubspot.rosetta.immutables.beans;

import java.util.Optional;

import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.hubspot.immutables.utils.WireSafeEnum;

public class WireSafeBean {
private WireSafeEnum<SimpleEnum> simple;
private WireSafeEnum<CustomEnum> custom;
private WireSafeEnum<SimpleEnum> simple;
private Optional<WireSafeEnum<SimpleEnum>> simpleMaybe;
private WireSafeEnum<CustomEnum> custom;
private Optional<WireSafeEnum<CustomEnum>> customMaybe;

public WireSafeEnum<SimpleEnum> getSimple() {
public WireSafeEnum<SimpleEnum> getSimple() {
return simple;
}

public Optional<WireSafeEnum<SimpleEnum>> getSimpleMaybe() {
return simpleMaybe;
}

public WireSafeEnum<CustomEnum> getCustom() {
return custom;
}

public Optional<WireSafeEnum<CustomEnum>> getCustomMaybe() {
return customMaybe;
}

public void setSimple(WireSafeEnum<SimpleEnum> simple) {
this.simple = simple;
}

public void setSimpleMaybe(Optional<WireSafeEnum<SimpleEnum>> simpleMaybe) {
this.simpleMaybe = simpleMaybe;
}

public void setCustom(WireSafeEnum<CustomEnum> custom) {
this.custom = custom;
}

public void setCustomMaybe(Optional<WireSafeEnum<CustomEnum>> customMaybe) {
this.customMaybe = customMaybe;
}

@Override
public String toString() {
return MoreObjects
.toStringHelper(WireSafeBean.class)
.add("simple", simple)
.add("custom", custom).toString();
.add("simpleMaybe", simpleMaybe)
.add("custom", custom)
.add("customMaybe", customMaybe)
.toString();
}

@Override
Expand All @@ -44,11 +67,13 @@ public boolean equals(Object o) {

WireSafeBean bean = (WireSafeBean) o;
return Objects.equal(simple, bean.simple) &&
Objects.equal(custom, bean.custom);
Objects.equal(simpleMaybe, bean.simpleMaybe) &&
Objects.equal(custom, bean.custom) &&
Objects.equal(customMaybe, bean.customMaybe);
}

@Override
public int hashCode() {
return Objects.hashCode(simple, custom);
return Objects.hashCode(simple, simpleMaybe, custom, customMaybe);
}
}