Skip to content

Commit

Permalink
Merge pull request #105 from HubSpot/asymetric_serialization
Browse files Browse the repository at this point in the history
Add support for asymetric property name serialization / deserialization
  • Loading branch information
suruuK authored Jun 12, 2024
2 parents ea87dae + 8908e28 commit d904847
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.hubspot.rosetta.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* like @JsonSetter only limited to Rosetta mapping/binding
*/
@Target(
{
ElementType.ANNOTATION_TYPE,
ElementType.FIELD,
ElementType.METHOD,
ElementType.PARAMETER,
}
)
@Retention(RetentionPolicy.RUNTIME)
@RosettaAnnotation
public @interface RosettaDeserializationProperty {
String USE_DEFAULT_NAME = "";

String value() default USE_DEFAULT_NAME;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.hubspot.rosetta.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* like @JsonGetter only limited to Rosetta mapping/binding
*/
@Target(
{
ElementType.ANNOTATION_TYPE,
ElementType.FIELD,
ElementType.METHOD,
ElementType.PARAMETER,
}
)
@Retention(RetentionPolicy.RUNTIME)
@RosettaAnnotation
public @interface RosettaSerializationProperty {
String USE_DEFAULT_NAME = "";

String value() default USE_DEFAULT_NAME;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.hubspot.rosetta.annotations.RosettaCreator;
import com.hubspot.rosetta.annotations.RosettaDeserializationProperty;
import com.hubspot.rosetta.annotations.RosettaDeserialize;
import com.hubspot.rosetta.annotations.RosettaIgnore;
import com.hubspot.rosetta.annotations.RosettaNaming;
import com.hubspot.rosetta.annotations.RosettaProperty;
import com.hubspot.rosetta.annotations.RosettaSerializationProperty;
import com.hubspot.rosetta.annotations.RosettaSerialize;
import com.hubspot.rosetta.annotations.RosettaValue;
import com.hubspot.rosetta.annotations.StoredAsJson;
import java.util.Optional;

public class RosettaAnnotationIntrospector extends NopAnnotationIntrospector {

Expand Down Expand Up @@ -118,20 +121,18 @@ public boolean hasCreatorAnnotation(Annotated a) {

@Override
public PropertyName findNameForSerialization(Annotated a) {
PropertyName propertyName = findRosettaPropertyName(a);
if (propertyName == null) {
propertyName = super.findNameForSerialization(a);
}
return propertyName;
return findRosettaGetterName(a)
.or(() -> findRosettaPropertyName(a))
.or(() -> Optional.ofNullable(super.findNameForSerialization(a)))
.orElse(null);
}

@Override
public PropertyName findNameForDeserialization(Annotated a) {
PropertyName propertyName = findRosettaPropertyName(a);
if (propertyName == null) {
propertyName = super.findNameForDeserialization(a);
}
return propertyName;
return findRosettaSetterName(a)
.or(() -> findRosettaPropertyName(a))
.or(() -> Optional.ofNullable(super.findNameForDeserialization(a)))
.orElse(null);
}

@Override
Expand Down Expand Up @@ -169,14 +170,34 @@ public Version version() {
return Version.unknownVersion();
}

private PropertyName findRosettaPropertyName(Annotated a) {
RosettaProperty ann = a.getAnnotation(RosettaProperty.class);
if (ann != null) {
return ann.value().isEmpty()
? PropertyName.USE_DEFAULT
: new PropertyName(ann.value());
}
return null;
private Optional<PropertyName> findRosettaPropertyName(Annotated a) {
return Optional
.ofNullable(a.getAnnotation(RosettaProperty.class))
.map(annotation ->
annotation.value().isEmpty()
? PropertyName.USE_DEFAULT
: new PropertyName(annotation.value())
);
}

private Optional<PropertyName> findRosettaGetterName(Annotated a) {
return Optional
.ofNullable(a.getAnnotation(RosettaSerializationProperty.class))
.map(annotation ->
annotation.value().isEmpty()
? PropertyName.USE_DEFAULT
: new PropertyName(annotation.value())
);
}

private Optional<PropertyName> findRosettaSetterName(Annotated a) {
return Optional
.ofNullable(a.getAnnotation(RosettaDeserializationProperty.class))
.map(annotation ->
annotation.value().isEmpty()
? PropertyName.USE_DEFAULT
: new PropertyName(annotation.value())
);
}

private Annotated getAnnotatedTypeFromAnnotatedMethod(AnnotatedMethod a) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.hubspot.rosetta.annotations;

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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hubspot.rosetta.Rosetta;
import com.hubspot.rosetta.beans.RosettaGetterBean;
import java.io.IOException;
import org.junit.Test;

public class RosettaGetterTest {

private static final String EXPECTED_ROSETTA_JSON =
"{\"jsonIgnoreRosettaUse\":\"Here\",\"mccartney_song_title\":\"Hey Jude\",\"other_value\":\"blah\"}";
private static final String ROSETTA_JSON =
"{\"jsonIgnoreRosettaUse\":\"Here\",\"mcCartneySongTitle\":\"Hey Jude\",\"otherValue\":\"blah\"}";
private static final String JACKSON_JSON =
"{\"mcCartneySongTitle\":\"Hey Jude\",\"otherValue\":\"blah\"}";

@Test
public void itWritesWithTheGetterName() throws JsonProcessingException {
RosettaGetterBean bean = new RosettaGetterBean();
bean.setMcCartneySongTitle("Hey Jude");
bean.setJsonIgnoreRosettaUse("Here");
bean.setSomeOtherValue("blah");
assertThat(Rosetta.getMapper().writeValueAsString(bean))
.isEqualTo(EXPECTED_ROSETTA_JSON);
assertThat(new ObjectMapper().writeValueAsString(bean)).isEqualTo(JACKSON_JSON);
}

@Test
public void itReadsThePropertyName() throws IOException {
RosettaGetterBean rosettaRead = Rosetta
.getMapper()
.readValue(ROSETTA_JSON, RosettaGetterBean.class);
assertThat(rosettaRead.getMcCartneySongTitle()).isEqualTo("Hey Jude");
assertThat(rosettaRead.getJsonIgnoreRosettaUse()).isNull();
assertThat(rosettaRead.getSomeOtherValue()).isEqualTo("blah");

RosettaGetterBean jsonRead = new ObjectMapper()
.readValue(JACKSON_JSON, RosettaGetterBean.class);
assertThat(jsonRead.getJsonIgnoreRosettaUse()).isNull();
assertThat(jsonRead.getMcCartneySongTitle()).isEqualTo("Hey Jude");
assertThat(jsonRead.getSomeOtherValue()).isEqualTo("blah");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.hubspot.rosetta.annotations;

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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hubspot.rosetta.Rosetta;
import com.hubspot.rosetta.beans.RosettaSetterBean;
import java.io.IOException;
import org.junit.Test;

public class RosettaSetterTest {

private static final String EXPECTED_ROSETTA_JSON =
"{\"mcCartneySongTitle\":\"Hey Jude\",\"otherValue\":\"blah\"}";
private static final String EXPECTED_JACKSON_JSON =
"{\"mcCartneySongTitle\":\"Hey Jude\",\"otherValue\":\"blah\"}";
private static final String ROSETTA_JSON =
"{\"mccartney_song_title\":\"Hey Jude\",\"jsonIgnoreRosettaUse\":\"Here\",\"other_value\":\"blah\"}";
private static final String JACKSON_JSON =
"{\"mcCartneySongTitle\":\"Hey Jude\",\"jsonIgnoreRosettaUse\":\"Here\",\"otherValue\":\"blah\"}";

@Test
public void itWritesWithThePropertyName() throws JsonProcessingException {
RosettaSetterBean bean = new RosettaSetterBean();
bean.setMcCartneySongTitle("Hey Jude");
bean.setJsonIgnoreRosettaUse("Here");
bean.setSomeOtherValue("blah");
assertThat(Rosetta.getMapper().writeValueAsString(bean))
.isEqualTo(EXPECTED_ROSETTA_JSON);
assertThat(new ObjectMapper().writeValueAsString(bean))
.isEqualTo(EXPECTED_JACKSON_JSON);
}

@Test
public void itReadsThePropertyName() throws IOException {
RosettaSetterBean rosettaRead = Rosetta
.getMapper()
.readValue(ROSETTA_JSON, RosettaSetterBean.class);
assertThat(rosettaRead.getMcCartneySongTitle()).isEqualTo("Hey Jude");
assertThat(rosettaRead.getJsonIgnoreRosettaUse()).isEqualTo("Here");
assertThat(rosettaRead.getSomeOtherValue()).isEqualTo("blah");

RosettaSetterBean jsonRead = new ObjectMapper()
.readValue(JACKSON_JSON, RosettaSetterBean.class);
assertThat(jsonRead.getJsonIgnoreRosettaUse()).isNull();
assertThat(jsonRead.getMcCartneySongTitle()).isEqualTo("Hey Jude");
assertThat(jsonRead.getSomeOtherValue()).isEqualTo("blah");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.hubspot.rosetta.beans;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.hubspot.rosetta.annotations.RosettaSerializationProperty;

public class RosettaGetterBean {

@RosettaSerializationProperty("mccartney_song_title")
private String mcCartneySongTitle;

@RosettaSerializationProperty
@JsonIgnore
private String jsonIgnoreRosettaUse;

@JsonProperty("otherValue")
@RosettaSerializationProperty("other_value")
private String someOtherValue;

public String getMcCartneySongTitle() {
return mcCartneySongTitle;
}

public RosettaGetterBean setMcCartneySongTitle(String mcCartneySongTitle) {
this.mcCartneySongTitle = mcCartneySongTitle;
return this;
}

public String getJsonIgnoreRosettaUse() {
return jsonIgnoreRosettaUse;
}

public String getSomeOtherValue() {
return someOtherValue;
}

public RosettaGetterBean setSomeOtherValue(String someOtherValue) {
this.someOtherValue = someOtherValue;
return this;
}

public RosettaGetterBean setJsonIgnoreRosettaUse(String jsonIgnoreRosettaUse) {
this.jsonIgnoreRosettaUse = jsonIgnoreRosettaUse;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.hubspot.rosetta.beans;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.hubspot.rosetta.annotations.RosettaDeserializationProperty;

public class RosettaSetterBean {

@RosettaDeserializationProperty("mccartney_song_title")
private String mcCartneySongTitle;

@RosettaDeserializationProperty
@JsonIgnore
private String jsonIgnoreRosettaUse;

@JsonProperty("otherValue")
@RosettaDeserializationProperty("other_value")
private String someOtherValue;

public String getMcCartneySongTitle() {
return mcCartneySongTitle;
}

public RosettaSetterBean setMcCartneySongTitle(String mcCartneySongTitle) {
this.mcCartneySongTitle = mcCartneySongTitle;
return this;
}

public String getSomeOtherValue() {
return someOtherValue;
}

public RosettaSetterBean setSomeOtherValue(String someOtherValue) {
this.someOtherValue = someOtherValue;
return this;
}

public String getJsonIgnoreRosettaUse() {
return jsonIgnoreRosettaUse;
}

public RosettaSetterBean setJsonIgnoreRosettaUse(String jsonIgnoreRosettaUse) {
this.jsonIgnoreRosettaUse = jsonIgnoreRosettaUse;
return this;
}
}

0 comments on commit d904847

Please sign in to comment.