// Copyright 2013 Square, Inc. package retrofit.converter; import com.google.protobuf.AbstractMessageLite; import retrofit.mime.TypedByteArray; import retrofit.mime.TypedInput; import retrofit.mime.TypedOutput; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * A {@link Converter} that reads and writes protocol buffers. */ public class ProtoConverter implements Converter { private static final String MIME_TYPE = "application/x-protobuf"; @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { if (!(type instanceof Class<?>)) { throw new IllegalArgumentException("Expected a raw Class<?> but was " + type); } Class<?> c = (Class<?>) type; if (!AbstractMessageLite.class.isAssignableFrom(c)) { throw new IllegalArgumentException("Expected a protobuf message but was " + c.getName()); } String mimeType = body.mimeType(); if (!MIME_TYPE.equals(mimeType)) { throw new ConversionException("Response content type was not a proto: " + mimeType); } try { Method parseFrom = c.getMethod("parseFrom", InputStream.class); return parseFrom.invoke(null, body.in()); } catch (InvocationTargetException e) { throw new ConversionException(c.getName() + ".parseFrom() failed", e.getCause()); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Expected a protobuf message but was " + c.getName()); } catch (IllegalAccessException e) { throw new AssertionError(); } catch (IOException e) { throw new ConversionException(e); } } @Override public TypedOutput toBody(Object object) { if (!(object instanceof AbstractMessageLite)) { throw new IllegalArgumentException( "Expected a protobuf message but was " + (object != null ? object.getClass().getName() : "null")); } byte[] bytes = ((AbstractMessageLite) object).toByteArray(); return new TypedByteArray(MIME_TYPE, bytes); } }