Package org.qi4j.api.json

Source Code of org.qi4j.api.json.JSONSerializer

package org.qi4j.api.json;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.json.JSONException;
import org.json.JSONObject;
import org.qi4j.api.Qi4j;
import org.qi4j.api.association.Association;
import org.qi4j.api.association.AssociationDescriptor;
import org.qi4j.api.association.AssociationStateHolder;
import org.qi4j.api.association.ManyAssociation;
import org.qi4j.api.composite.Composite;
import org.qi4j.api.composite.CompositeInstance;
import org.qi4j.api.entity.EntityComposite;
import org.qi4j.api.entity.EntityReference;
import org.qi4j.api.entity.Identity;
import org.qi4j.api.property.Property;
import org.qi4j.api.property.PropertyDescriptor;
import org.qi4j.api.property.StateHolder;
import org.qi4j.api.type.*;
import org.qi4j.api.util.Dates;
import org.qi4j.api.value.ValueComposite;
import org.qi4j.api.value.ValueDescriptor;
import org.qi4j.functional.Function;
import org.qi4j.functional.Functions;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
* TODO
*/
public abstract class JSONSerializer
{
    private static Map<Class, Function<Object, Object>> typeFunctions = new HashMap<Class, Function<Object, Object>>();

    public static <T> void registerSerializer( Class<T> type, Function<T, Object> typeFunction )
    {
        typeFunctions.put( type, (Function<Object, Object>) typeFunction );
    }

    static
    {
        registerSerializer( String.class, Functions.<Object, String>identity() );

        // Primitive types
        registerSerializer( Boolean.class, Functions.<Object, Boolean>identity() );
        registerSerializer( Integer.class, Functions.<Object, Integer>identity() );
        registerSerializer( Long.class, Functions.<Object, Long>identity() );
        registerSerializer( Short.class, Functions.<Object, Short>identity() );
        registerSerializer( Byte.class, Functions.<Object, Byte>identity() );
        registerSerializer( Float.class, Functions.<Object, Float>identity() );
        registerSerializer( Double.class, Functions.<Object, Double>identity() );

        // Number types
        registerSerializer( BigDecimal.class, new Function<BigDecimal, Object>()
        {
            @Override
            public Object map( BigDecimal bigDecimal )
            {
                return bigDecimal;
            }
        } );

        registerSerializer( BigInteger.class, new Function<BigInteger, Object>()
        {
            @Override
            public Object map( BigInteger bigInteger )
            {
                return bigInteger;
            }
        } );

        // Date types
        registerSerializer( Date.class, new Function<Date, Object>()
        {
            @Override
            public Object map( Date date )
            {
                return Dates.toUtcString( date );
            }
        } );

        registerSerializer( DateTime.class, new Function<DateTime, Object>()
        {
            @Override
            public Object map( DateTime date )
            {
                return date.toString();
            }
        } );
        registerSerializer( LocalDateTime.class, new Function<LocalDateTime, Object>()
        {
            @Override
            public Object map( LocalDateTime date )
            {
                return date.toString();
            }
        } );
        registerSerializer( LocalDate.class, new Function<LocalDate, Object>()
        {
            @Override
            public Object map( LocalDate date )
            {
                return date.toString();
            }
        } );

        // Other supported types
        registerSerializer( EntityReference.class, new Function<EntityReference, Object>()
        {
            @Override
            public Object map( EntityReference date )
            {
                return date.toString();
            }
        } );
    }

    private boolean includeTypeInformation = true;

    public void setIncludeType(boolean includeTypeInformation)
    {
        this.includeTypeInformation = includeTypeInformation;
    }

    public void serialize( ValueComposite value ) throws JSONException
    {
        ValueDescriptor valueDescriptor = (ValueDescriptor) Qi4j.DESCRIPTOR_FUNCTION.map(value);

        ValueType valueType = valueDescriptor.valueType();

        serialize( value, valueType );
    }

    public void serialize( Object value, ValueType valueType ) throws JSONException
    {
        // Check for null first
        if( value == null )
        {
            value( null );
            return;
        }

        // Try functions second
        Function<Object, Object> typeFunction = typeFunctions.get( valueType.type() );
        if( typeFunction != null )
        {
            value( typeFunction.map( value ) );
        } else if( valueType instanceof ValueCompositeType ) // Handle all other types
        {
            ValueCompositeType valueCompositeType = (ValueCompositeType) valueType;

            objectStart();
            ValueComposite valueComposite = (ValueComposite) value;

            if( !valueCompositeType.type().equals( Qi4j.DESCRIPTOR_FUNCTION.map( valueComposite ).type() ) )
            {
                // Actual value is a subtype - use it instead
                ValueDescriptor valueDescriptor = (ValueDescriptor) Qi4j.DESCRIPTOR_FUNCTION.map( valueComposite );

                valueCompositeType = valueDescriptor.valueType();

                if (includeTypeInformation)
                    key("_type").value( valueDescriptor.valueType().type().getName() );
            }

            AssociationStateHolder state = (AssociationStateHolder) Qi4j.INSTANCE_FUNCTION.map( valueComposite ).state();
            for( PropertyDescriptor persistentProperty : valueCompositeType.properties() )
            {
                Property<?> property = state.propertyFor( persistentProperty.accessor() );
                key( persistentProperty.qualifiedName().name() ).serialize( property.get(), persistentProperty.valueType() );
            }
            for( AssociationDescriptor associationDescriptor : valueCompositeType.associations() )
            {
                Association<?> association = state.associationFor( associationDescriptor.accessor() );

                Object instance = association.get();
                if (instance != null)
                    key( associationDescriptor.qualifiedName().name() ).value( ((Identity)instance).identity().get() );
            }
            for( AssociationDescriptor associationDescriptor : valueCompositeType.manyAssociations() )
            {
                ManyAssociation<?> manyAssociation = state.manyAssociationFor( associationDescriptor.accessor() );
                key( associationDescriptor.qualifiedName().name() ).serialize( manyAssociation.toList(), new CollectionType( List.class, new ValueType( String.class ) ) );
            }
            objectEnd();
        } else if( valueType instanceof CollectionType )
        {
            CollectionType collectionType = (CollectionType) valueType;

            arrayStart();

            Collection collection = (Collection) value;
            for( Object collectionValue : collection )
            {
                serialize( collectionValue, collectionType.collectedType() );
            }

            arrayEnd();

        } else if( valueType instanceof MapType )
        {
            arrayStart();

            MapType mapType = (MapType) valueType;
            Map map = (Map) value;
            Set<Map.Entry> set = map.entrySet();
            for( Map.Entry<Object, Object> entry : set )
            {
                objectStart();
                key( "key" ).serialize( entry.getKey(), mapType.getKeyType() );
                key( "value" ).serialize( entry.getValue(), mapType.getValueType() );
                objectEnd();
            }

            arrayEnd();

        } else if (valueType instanceof EnumType )
        {
            value( value.toString() );
        } else
        {
/* TODO How to handle deserialization?
            // Try for the actual value class first
            typeFunction = typeFunctions.get( value.getClass() );
            if( typeFunction != null )
            {
                value( typeFunction.map( value ) );
                return;
            }
*/

            // Check if we are serializing an Entity
            if( value instanceof EntityComposite )
            {
                // Store reference instead
                value = EntityReference.getEntityReference( value );
            } else if( value instanceof ValueComposite )
            {
                // Serialize ValueComposite JSON instead
                try
                {
                    JSONObjectSerializer JSONObjectSerializer = new JSONObjectSerializer();
                    JSONObjectSerializer.serialize( (ValueComposite) value );

                    JSONObject object = (JSONObject) JSONObjectSerializer.getRoot();

                    ValueDescriptor descriptor = (ValueDescriptor) Qi4j.DESCRIPTOR_FUNCTION.map( (Compositevalue );

                    if (includeTypeInformation)
                        object.put( "_type", descriptor.type().getName() );
                    value( object );
                    return;
                } catch( JSONException e )
                {
                    throw new IllegalStateException( "Could not JSON serialize value", e );
                }
            }

            // Serialize value
            try
            {
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream( bout );
                out.writeUnshared( value );
                out.close();
                byte[] bytes = Base64Encoder.encode( bout.toByteArray(), true );
                String stringValue = new String( bytes, "UTF-8" );
                value(stringValue);
            } catch( IOException e )
            {
                throw new IllegalArgumentException( "Could not serialize value", e );
            }
        }
    }

    public abstract JSONSerializer key(String key) throws JSONException;

    public abstract JSONSerializer value(Object value) throws JSONException;

    public abstract JSONSerializer objectStart() throws JSONException;

    public abstract JSONSerializer objectEnd() throws JSONException;

    public abstract JSONSerializer arrayStart() throws JSONException;

    public abstract JSONSerializer arrayEnd() throws JSONException;
}
TOP

Related Classes of org.qi4j.api.json.JSONSerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.