View Javadoc

1   package org.apache.directmemory.serialization.protobuf;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static java.lang.String.format;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  import java.lang.reflect.Method;
27  
28  import org.apache.directmemory.serialization.Serializer;
29  
30  import com.google.protobuf.GeneratedMessage;
31  import com.google.protobuf.Message;
32  
33  public final class ProtobufSerializer
34      implements Serializer
35  {
36  
37      private static final String NEW_BUILDER_METHOD = "newBuilder";
38  
39      /**
40       * {@inheritDoc}
41       */
42      @Override
43      public <T> byte[] serialize( T obj )
44          throws IOException
45      {
46          checkProtobufMessage( obj.getClass() );
47  
48          final ByteArrayOutputStream baos = new ByteArrayOutputStream();
49  
50          try
51          {
52              ( (Message) obj ).writeTo( baos );
53          }
54          finally
55          {
56              try
57              {
58                  baos.close();
59              }
60              catch ( Exception e )
61              {
62                  // close quietly
63              }
64          }
65  
66          return baos.toByteArray();
67      }
68  
69      /**
70       * {@inheritDoc}
71       */
72      @Override
73      public <T> T deserialize( byte[] source, Class<T> clazz )
74          throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
75      {
76          clazz = checkProtobufMessage( clazz );
77  
78          try
79          {
80              Method newBuilder = clazz.getMethod( NEW_BUILDER_METHOD );
81  
82              // fixme no idea ATM how to fix type inference here
83              GeneratedMessage.Builder builder = (GeneratedMessage.Builder) newBuilder.invoke( clazz );
84  
85              @SuppressWarnings( "unchecked" ) // cast should be safe since it is driven by the type
86              T deserialized = (T) builder.mergeFrom( source ).build();
87  
88              return deserialized;
89          }
90          catch ( Throwable t )
91          {
92              throw new IOException( t );
93          }
94      }
95  
96      private static <T> Class<T> checkProtobufMessage( Class<T> clazz )
97      {
98          if ( !Message.class.isAssignableFrom( clazz ) )
99          {
100             throw new IllegalArgumentException( format( "Class %s cannot be serialized via Google Protobuf, it is not a %s",
101                                                         clazz.getName(),
102                                                         Message.class.getName() ) );
103         }
104         return clazz;
105     }
106 
107 }