Created
June 18, 2018 12:40
-
-
Save miere/7fe36308bfdbc5872d2b68f77ab2f3fc to your computer and use it in GitHub Desktop.
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
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