Skip to content

Instantly share code, notes, and snippets.

@edwise
Last active February 22, 2019 09:27
Show Gist options
  • Save edwise/0f493652b09ee4c3e28a9143fe597bcd to your computer and use it in GitHub Desktop.
Save edwise/0f493652b09ee4c3e28a9143fe597bcd to your computer and use it in GitHub Desktop.
Serialize to String Lists with custom objects
/**
* Serialize a collection of custom objects. The properties should be "string compatible".
*
* @param list collection to serialize.
* @param clazz type of the the collection.
* @return collection serialized in string.
*/
public static <T> String serializeCustomObjectsCollection(Collection<T> list, Class<T> clazz) {
return Optional.ofNullable(list)
.map(listValue -> listValue.stream()
.map(item -> serializeMap(extractProperties(item, clazz)))
.collect(Collectors.joining(SUPER_ITEM_SEPARATOR)))
.orElse(null);
}
private static <T> Map<String, Object> extractProperties(T item, Class<T> clazz) {
return Stream.of(clazz.getDeclaredFields())
.filter(field -> !field.isSynthetic())
.collect(Collectors.toMap(Field::getName,
field -> readProperty(clazz, item, field)));
}
private static <T> Object readProperty(Class<T> clazz, T item, Field field) {
return Try.ofFailable(() -> new PropertyDescriptor(field.getName(), clazz).getReadMethod().invoke(item))
.onFailure(ex -> log.error("Reading property {} for class {}", field.getName(), clazz.getName(), ex))
.orElse(org.apache.commons.lang3.StringUtils.EMPTY);
}
/**
* Deserialize a collection of custom objects from string to Collection<T>.
* IMPORTANT: the properties of the type should be or string or having a constructor with string parameter (Ex: BigDecimal)
*
* @param serializedCollection string with the collection serialized
* @param clazz type of the collection.
* @return collection.
*/
public static <T> Collection<T> deserializeCustomObjectsCollection(String serializedCollection, Class<T> clazz) {
return Optional.ofNullable(serializedCollection)
.map(listValue -> {
String[] propertiesList = serializedCollection.split(SUPER_ITEM_SEPARATOR);
return Stream.of(propertiesList)
.map(map -> createItem(clazz, deserializeMap(map, String::toString)))
.collect(Collectors.toList());
})
.orElse(Collections.emptyList());
}
private static <T> T createItem(Class<T> clazz, Map<String, String> properties) {
T item = createInstance(clazz);
properties.forEach((key, value) -> setProperty(key, value, item, clazz));
return item;
}
private static <T> T createInstance(Class<T> clazz) {
try {
return clazz.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
log.error("Creating object of type {}", clazz.getName(), e);
return null;
}
}
private static <T> void setProperty(String fieldName, String value, T item, Class<T> clazz) {
try {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, clazz);
Class<?> parameterType = propertyDescriptor.getWriteMethod().getParameterTypes()[0];
if (parameterType.equals(String.class)) {
propertyDescriptor.getWriteMethod().invoke(item, value);
} else {
Object valueNoString = parameterType.getConstructor(String.class).newInstance(value);
propertyDescriptor.getWriteMethod().invoke(item, valueNoString);
}
} catch (IllegalAccessException | InvocationTargetException | IntrospectionException | NoSuchMethodException |
InstantiationException e) {
log.error("Setting property {} for class {}", fieldName, clazz.getName(), e);
}
}
@DataProvider(name = "customObjectsCollectionSerialize")
public static Object[][] customObjectsCollectionSerialize() {
return new Object[][] {
{Arrays.asList(new ThirdPartyData("irrelevantSegmentId1", new BigDecimal("2.45")),
new ThirdPartyData("irrelevantSegmentId2", new BigDecimal("23.12"))),
"cost=2.45:segmentId=irrelevantSegmentId1&&cost=23.12:segmentId=irrelevantSegmentId2"},
{Collections.singletonList(new ThirdPartyData("irrelevantSegmentId1", new BigDecimal("2.45"))),
"cost=2.45:segmentId=irrelevantSegmentId1"}
};
}
@Test(dataProvider = "customObjectsCollectionSerialize")
public void serializeCustomObjectsCollectionShouldExecuteSerialization(List<ThirdPartyData> collection, String expected) {
String result = RedisUtils.serializeCustomObjectsCollection(collection, ThirdPartyData.class);
assertThat(result, is(expected));
}
@DataProvider(name = "customObjectsCollectionDeserialize")
public static Object[][] customObjectsCollectionDeserialize() {
return new Object[][] {
{"cost=2.45:segmentId=irrelevantSegmentId1&&cost=23.12:segmentId=irrelevantSegmentId2",
Arrays.asList(new ThirdPartyData("irrelevantSegmentId1", new BigDecimal("2.45")),
new ThirdPartyData("irrelevantSegmentId2", new BigDecimal("23.12")))},
{"cost=2.45:segmentId=irrelevantSegmentId1",
Collections.singletonList(new ThirdPartyData("irrelevantSegmentId1", new BigDecimal("2.45")))}
};
}
@Test(dataProvider = "customObjectsCollectionDeserialize")
public void deserializeCustomObjectsCollectionShouldExecuteDeserialization(String serialized,
List<ThirdPartyData> expectedList) {
Collection<ThirdPartyData> thirdPartyData =
RedisUtils.deserializeCustomObjectsCollection(serialized, ThirdPartyData.class);
assertThat(thirdPartyData, containsInAnyOrder(expectedList.toArray()));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment