Last active
February 22, 2019 09:27
-
-
Save edwise/0f493652b09ee4c3e28a9143fe597bcd to your computer and use it in GitHub Desktop.
Serialize to String Lists with custom objects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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