View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.server.rest.repr;
21  
22  import java.lang.annotation.ElementType;
23  import java.lang.annotation.Retention;
24  import java.lang.annotation.RetentionPolicy;
25  import java.lang.annotation.Target;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.util.HashMap;
29  import java.util.Map;
30  import java.util.concurrent.ConcurrentHashMap;
31  
32  public abstract class ObjectRepresentation extends MappingRepresentation
33  {
34      @Target( ElementType.METHOD )
35      @Retention( RetentionPolicy.RUNTIME )
36      protected @interface Mapping
37      {
38          String value();
39      }
40  
41      private static Map<Class<?>, Map<String, PropertyGetter>> serializations = new ConcurrentHashMap<Class<?>, Map<String, PropertyGetter>>();
42  
43      private final Map<String, PropertyGetter> serialization = serialization( getClass() );
44  
45      ObjectRepresentation( RepresentationType type )
46      {
47          super( type );
48      }
49  
50      public ObjectRepresentation( String type )
51      {
52          super( type );
53      }
54  
55      private static Map<String, PropertyGetter> serialization(
56              Class<? extends ObjectRepresentation> type )
57      {
58          Map<String, PropertyGetter> serialization = serializations.get( type );
59          if ( serialization == null )
60          {
61              synchronized ( type )
62              {
63                  serialization = serializations.get( type );
64                  if ( serialization == null )
65                  {
66                      serialization = new HashMap<String, PropertyGetter>();
67                      for ( Method method : type.getMethods() )
68                      {
69                          Mapping property = method.getAnnotation( Mapping.class );
70                          if ( property != null )
71                          {
72                              serialization.put( property.value(), getter( method ) );
73                          }
74                      }
75                  }
76              }
77          }
78          return serialization;
79      }
80  
81      private static PropertyGetter getter( final Method method )
82      {
83          // If this turns out to be a bottle neck we could use a byte code
84          // generation library, such as ASM, instead of reflection.
85          return new PropertyGetter( method )
86          {
87              @Override
88              Object get( ObjectRepresentation object )
89              {
90                  Throwable e;
91                  try
92                  {
93                      return method.invoke( object );
94                  }
95                  catch ( InvocationTargetException ex )
96                  {
97                      e = ex.getTargetException();
98                      if ( e instanceof RuntimeException )
99                      {
100                         throw (RuntimeException) e;
101                     }
102                     else if ( e instanceof Error )
103                     {
104                         throw (Error) e;
105                     }
106                 }
107                 catch ( Exception ex )
108                 {
109                     e = ex;
110                 }
111                 throw new IllegalStateException( "Serialization failure", e );
112             }
113         };
114     }
115 
116     private static abstract class PropertyGetter
117     {
118         PropertyGetter( Method method )
119         {
120             if ( method.getParameterTypes().length != 0 )
121             {
122                 throw new IllegalStateException(
123                         "Property getter method may not have any parameters." );
124             }
125             if ( !Representation.class.isAssignableFrom( (Class<?>) method.getReturnType() ) )
126             {
127                 throw new IllegalStateException(
128                         "Property getter must return Representation object." );
129             }
130         }
131 
132         void putTo( MappingSerializer serializer, ObjectRepresentation object, String key )
133         {
134             Object value = get( object );
135             if ( value != null ) ( (Representation) value ).putTo( serializer, key );
136         }
137 
138         abstract Object get( ObjectRepresentation object );
139     }
140 
141     @Override
142     protected final void serialize( MappingSerializer serializer )
143     {
144         for ( Map.Entry<String, PropertyGetter> property : serialization.entrySet() )
145         {
146             property.getValue().putTo( serializer, this, property.getKey() );
147         }
148         extraData( serializer );
149     }
150 
151     void extraData( MappingSerializer serializer )
152     {
153     }
154 }