All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.server.rest.repr.ObjectRepresentation Maven / Gradle / Ivy

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.server.rest.repr;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class ObjectRepresentation extends MappingRepresentation
{
    @Target( ElementType.METHOD )
    @Retention( RetentionPolicy.RUNTIME )
    protected @interface Mapping
    {
        String value();
    }

    private static final ConcurrentHashMap, Map> serializations =
            new ConcurrentHashMap<>();

    private final Map serialization = serialization( getClass() );

    public ObjectRepresentation( RepresentationType type )
    {
        super( type );
    }

    public ObjectRepresentation( String type )
    {
        super( type );
    }

    private static Map serialization( Class type )
    {
        Map serialization = serializations.computeIfAbsent(
                type, ObjectRepresentation::buildSerialization );
        return serialization;
    }

    private static Map buildSerialization( Class type )
    {
        Map serialization;
        serialization = new HashMap<>();
        for ( Method method : type.getMethods() )
        {
            Mapping property = method.getAnnotation( Mapping.class );
            if ( property != null )
            {
                serialization.put( property.value(), getter( method ) );
            }
        }
        return serialization;
    }

    private static PropertyGetter getter( final Method method )
    {
        // If this turns out to be a bottle neck we could use a byte code
        // generation library, such as ASM, instead of reflection.
        return new PropertyGetter( method )
        {
            @Override
            Object get( ObjectRepresentation object )
            {
                Throwable e;
                try
                {
                    return method.invoke( object );
                }
                catch ( InvocationTargetException ex )
                {
                    e = ex.getTargetException();
                    if ( e instanceof RuntimeException )
                    {
                        throw (RuntimeException) e;
                    }
                    else if ( e instanceof Error )
                    {
                        throw (Error) e;
                    }
                }
                catch ( Exception ex )
                {
                    e = ex;
                }
                throw new IllegalStateException( "Serialization failure", e );
            }
        };
    }

    private abstract static class PropertyGetter
    {
        PropertyGetter( Method method )
        {
            if ( method.getParameterTypes().length != 0 )
            {
                throw new IllegalStateException( "Property getter method may not have any parameters." );
            }
            if ( !Representation.class.isAssignableFrom( method.getReturnType() ) )
            {
                throw new IllegalStateException( "Property getter must return Representation object." );
            }
        }

        void putTo( MappingSerializer serializer, ObjectRepresentation object, String key )
        {
            Object value = get( object );
            if ( value != null )
            {
                ((Representation) value).putTo( serializer, key );
            }
        }

        abstract Object get( ObjectRepresentation object );
    }

    @Override
    protected final void serialize( MappingSerializer serializer )
    {
        for ( Map.Entry property : serialization.entrySet() )
        {
            property.getValue()
                    .putTo( serializer, this, property.getKey() );
        }
        extraData( serializer );
    }

    protected void extraData( MappingSerializer serializer )
    {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy