Skip to content

Instantly share code, notes, and snippets.

@miere
Created June 18, 2018 12:40
Show Gist options
  • Save miere/7fe36308bfdbc5872d2b68f77ab2f3fc to your computer and use it in GitHub Desktop.
Save miere/7fe36308bfdbc5872d2b68f77ab2f3fc to your computer and use it in GitHub Desktop.
import java.lang.reflect.*;
import java.util.*;
import java.util.function.Function;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import lombok.*;
@SuppressWarnings( "unchecked" )
public abstract class DynamoReflectiveSerializer {
private static final Map<Class, Function<Field, FieldAttributeValueReader>> fieldHoldersFactories = new HashMap<>();
private static final Map<Class, Function<Object, AttributeValue>> typeHolder = new HashMap<>();
private static final AttributeValue nullValue = new AttributeValue().withNULL( true );
private static final Function<Field, FieldAttributeValueReader> complexObjectAttributeHolder = ComplexObjectAttributeValue::new;
static {
fieldHoldersFactories.put( String.class, StringAttributeValue::new );
fieldHoldersFactories.put( int.class, IntegerAttributeValue::new );
fieldHoldersFactories.put( Integer.class, IntegerAttributeValue::new );
fieldHoldersFactories.put( long.class, LongAttributeValue::new );
fieldHoldersFactories.put( Long.class, LongAttributeValue::new );
fieldHoldersFactories.put( double.class, DoubleAttributeValue::new );
fieldHoldersFactories.put( Double.class, DoubleAttributeValue::new );
fieldHoldersFactories.put( boolean.class, BooleanAttributeValue::new );
fieldHoldersFactories.put( Boolean.class, BooleanAttributeValue::new );
fieldHoldersFactories.put( List.class, ListAttributeValue::new );
fieldHoldersFactories.put( Map.class, MapAttributeValue::new );
}
static {
typeHolder.put( String.class, o -> AttributeValue.create( o.toString() ) );
typeHolder.put( int.class, o -> AttributeValue.create( (Integer)o ) );
typeHolder.put( Integer.class, o -> AttributeValue.create( (Integer)o ) );
typeHolder.put( long.class, o -> AttributeValue.create( (Long)o ) );
typeHolder.put( Long.class, o -> AttributeValue.create( (Long)o ) );
typeHolder.put( double.class, o -> AttributeValue.create( (Double)o ) );
typeHolder.put( Double.class, o -> AttributeValue.create( (Double)o ) );
typeHolder.put( boolean.class, o -> AttributeValue.create( (Boolean)o ) );
typeHolder.put( Boolean.class, o -> AttributeValue.create( (Boolean)o ) );
}
public static AttributeValue serialize( Object object ) {
if ( object == null ) return nullValue;
return typeHolder
.computeIfAbsent( object.getClass(), DynamoReflectiveSerializer::compile )
.apply( object );
}
private static Function<Object, AttributeValue> compile( Class clazz ) {
final List<FieldAttributeValueReader> attributes = new ArrayList<>();
while ( !Object.class.equals( clazz ) ) {
for ( Field field : clazz.getDeclaredFields() ) {
if ( Modifier.isStatic( field.getModifiers() ) )
continue;
field.setAccessible( true );
val holder = fieldHoldersFactories.getOrDefault( field.getType(), complexObjectAttributeHolder );
attributes.add( holder.apply( field ) );
}
clazz = clazz.getSuperclass();
}
return new ComplexObjectAttributeValueReader( attributes );
}
@Value
static class ComplexObjectAttributeValueReader implements Function<Object, AttributeValue> {
final List<FieldAttributeValueReader> fields;
@Override
public AttributeValue apply(Object o) {
val attributes = new HashMap<String, AttributeValue>();
for ( FieldAttributeValueReader field : fields ) {
attributes.put( field.getField().getName(), field.read( o ) );
}
return AttributeValue.create().withM( attributes );
}
}
interface FieldAttributeValueReader {
Field getField();
default AttributeValue read( Object object ) {
try {
return get( object );
} catch ( IllegalAccessException e ) {
throw new IllegalStateException( e );
}
}
AttributeValue get( Object object ) throws IllegalAccessException;
}
@Value
static class BooleanAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get( Object object ) throws IllegalAccessException {
val v = (Boolean) field.get( object );
if ( v == null ) return nullValue;
return AttributeValue.create( v );
}
}
@Value
static class IntegerAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get( Object object ) throws IllegalAccessException {
val v = (Integer) field.get( object );
if ( v == null ) return nullValue;
return AttributeValue.create( v );
}
}
@Value
static class LongAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get( Object object ) throws IllegalAccessException {
val v = (Long) field.get( object );
if ( v == null ) return nullValue;
return AttributeValue.create( v );
}
}
@Value
static class DoubleAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get( Object object ) throws IllegalAccessException {
return AttributeValue.create( (Double) field.get( object ) );
}
}
@Value
static class StringAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get( Object object ) throws IllegalAccessException {
return AttributeValue.create( (String) field.get( object ) );
}
}
@Value
static class ListAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get(Object object) throws IllegalAccessException {
val list = (List<Object>)field.get( object );
if ( list == null || list.isEmpty() )
return nullValue;
val newList = new ArrayList<AttributeValue>();
list.forEach( DynamoReflectiveSerializer::serialize );
return AttributeValue.create().withL( newList );
}
}
@Value
static class MapAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get(Object object) throws IllegalAccessException {
val list = (Map<String, Object>)field.get( object );
if ( list == null || list.isEmpty() )
return nullValue;
val newMap = new HashMap<String, AttributeValue>();
list.forEach( (k,v) -> newMap.put( k, serialize( v ) ) );
return AttributeValue.create().withM( newMap );
}
}
@Value
static class ComplexObjectAttributeValue implements FieldAttributeValueReader {
final Field field;
@Override
public AttributeValue get(Object object) throws IllegalAccessException {
val v = field.get( object );
if ( v == null )
return nullValue;
return serialize( v );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment