change java to uniform message, revert TestValidDataForType's parameters
diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java
index 3a944b5..15aaed9 100644
--- a/conformance/ConformanceJava.java
+++ b/conformance/ConformanceJava.java
@@ -1,13 +1,18 @@
 import com.google.protobuf.ByteString;
+import com.google.protobuf.AbstractMessage;
+import com.google.protobuf.Parser;
 import com.google.protobuf.CodedInputStream;
 import com.google.protobuf.conformance.Conformance;
 import com.google.protobuf.InvalidProtocolBufferException;
 import com.google.protobuf_test_messages.proto3.TestMessagesProto3;
+import com.google.protobuf_test_messages.proto3.TestMessagesProto3.TestAllTypes;
 import com.google.protobuf_test_messages.proto2.TestMessagesProto2;
+import com.google.protobuf_test_messages.proto2.TestMessagesProto2.TestAllTypesProto2;
+import com.google.protobuf.ExtensionRegistry;
 import com.google.protobuf.util.JsonFormat;
 import com.google.protobuf.util.JsonFormat.TypeRegistry;
-import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 
 class ConformanceJava {
   private int testCount = 0;
@@ -51,275 +56,100 @@
     buf[3] = (byte)(val >> 24);
     writeToStdout(buf);
   }
-
-  private enum BinaryDecoder {
-    BYTE_STRING_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        return TestMessagesProto3.TestAllTypes.parseFrom(bytes);
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        return TestMessagesProto2.TestAllTypesProto2.parseFrom(bytes);
-      }
-    },
-    BYTE_ARRAY_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        return TestMessagesProto3.TestAllTypes.parseFrom(bytes.toByteArray());
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        return TestMessagesProto2.TestAllTypesProto2.parseFrom(bytes.toByteArray());
-      }
-    },
-    ARRAY_BYTE_BUFFER_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        ByteBuffer buffer = ByteBuffer.allocate(bytes.size());
-        bytes.copyTo(buffer);
-        buffer.flip();
-        try {
-          return TestMessagesProto3.TestAllTypes.parseFrom(CodedInputStream.newInstance(buffer));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        ByteBuffer buffer = ByteBuffer.allocate(bytes.size());
-        bytes.copyTo(buffer);
-        buffer.flip();
-        try {
-          return TestMessagesProto2.TestAllTypesProto2.parseFrom(CodedInputStream.newInstance(buffer));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-    },
-    READONLY_ARRAY_BYTE_BUFFER_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        try {
-          return TestMessagesProto3.TestAllTypes.parseFrom(
-              CodedInputStream.newInstance(bytes.asReadOnlyByteBuffer()));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        try {
-          return TestMessagesProto2.TestAllTypesProto2.parseFrom(
-              CodedInputStream.newInstance(bytes.asReadOnlyByteBuffer()));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-    },
-    DIRECT_BYTE_BUFFER_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
-        bytes.copyTo(buffer);
-        buffer.flip();
-        try {
-          return TestMessagesProto3.TestAllTypes.parseFrom(CodedInputStream.newInstance(buffer));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
-        bytes.copyTo(buffer);
-        buffer.flip();
-        try {
-          return TestMessagesProto2.TestAllTypesProto2
-              .parseFrom(CodedInputStream.newInstance(buffer));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-    },
-    READONLY_DIRECT_BYTE_BUFFER_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
-        bytes.copyTo(buffer);
-        buffer.flip();
-        try {
-          return TestMessagesProto3.TestAllTypes.parseFrom(
-              CodedInputStream.newInstance(buffer.asReadOnlyBuffer()));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
-        bytes.copyTo(buffer);
-        buffer.flip();
-        try {
-          return TestMessagesProto2.TestAllTypesProto2.parseFrom(
-              CodedInputStream.newInstance(buffer.asReadOnlyBuffer()));
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based ByteBuffer should not throw IOException.", e);
-        }
-      }
-    },
-    INPUT_STREAM_DECODER() {
-      @Override
-      public TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        try {
-          return TestMessagesProto3.TestAllTypes.parseFrom(bytes.newInput());
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based InputStream should not throw IOException.", e);
-        }
-      }
-      @Override
-      public TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-          throws InvalidProtocolBufferException {
-        try {
-          return TestMessagesProto2.TestAllTypesProto2.parseFrom(bytes.newInput());
-        } catch (InvalidProtocolBufferException e) {
-          throw e;
-        } catch (IOException e) {
-          throw new RuntimeException(
-              "ByteString based InputStream should not throw IOException.", e);
-        }
-      }
-    };
-
-    public abstract TestMessagesProto3.TestAllTypes parseProto3(ByteString bytes)
-        throws InvalidProtocolBufferException;
-    public abstract TestMessagesProto2.TestAllTypesProto2 parseProto2(ByteString bytes)
-        throws InvalidProtocolBufferException;
-  }
-
-  private TestMessagesProto3.TestAllTypes parseBinaryToProto3(ByteString bytes)
-      throws InvalidProtocolBufferException {
-    TestMessagesProto3.TestAllTypes[] messages =
-        new TestMessagesProto3.TestAllTypes[BinaryDecoder.values().length];
-    InvalidProtocolBufferException[] exceptions =
-        new InvalidProtocolBufferException[BinaryDecoder.values().length];
-
-    boolean hasMessage = false;
-    boolean hasException = false;
-    for (int i = 0; i < BinaryDecoder.values().length; ++i) {
-      try {
-        messages[i] = BinaryDecoder.values()[i].parseProto3(bytes);
-        hasMessage = true;
-      } catch (InvalidProtocolBufferException e) {
-        exceptions[i] = e;
-        hasException = true;
-      }
-    }
-
-    if (hasMessage && hasException) {
-      StringBuilder sb =
-          new StringBuilder("Binary decoders disagreed on whether the payload was valid.\n");
-      for (int i = 0; i < BinaryDecoder.values().length; ++i) {
-        sb.append(BinaryDecoder.values()[i].name());
-        if (messages[i] != null) {
-          sb.append(" accepted the payload.\n");
-        } else {
-          sb.append(" rejected the payload.\n");
-        }
-      }
-      throw new RuntimeException(sb.toString());
-    }
-
-    if (hasException) {
-      // We do not check if exceptions are equal. Different implementations may return different
-      // exception messages. Throw an arbitrary one out instead.
-      throw exceptions[0];
-    }
-
-    // Fast path comparing all the messages with the first message, assuming equality being
-    // symmetric and transitive.
-    boolean allEqual = true;
-    for (int i = 1; i < messages.length; ++i) {
-      if (!messages[0].equals(messages[i])) {
-        allEqual = false;
-        break;
-      }
-    }
-
-    // Slow path: compare and find out all unequal pairs.
-    if (!allEqual) {
-      StringBuilder sb = new StringBuilder();
-      for (int i = 0; i < messages.length - 1; ++i) {
-        for (int j = i + 1; j < messages.length; ++j) {
-          if (!messages[i].equals(messages[j])) {
-            sb.append(BinaryDecoder.values()[i].name())
-                .append(" and ")
-                .append(BinaryDecoder.values()[j].name())
-                .append(" parsed the payload differently.\n");
-          }
-        }
-      }
-      throw new RuntimeException(sb.toString());
-    }
-
-    return messages[0];
-  }
   
-  private TestMessagesProto2.TestAllTypesProto2 parseBinaryToProto2(ByteString bytes)
+  private enum BinaryDecoderType {
+    BTYE_STRING_DECODER,
+    BYTE_ARRAY_DECODER,
+    ARRAY_BYTE_BUFFER_DECODER,
+    READONLY_ARRAY_BYTE_BUFFER_DECODER,
+    DIRECT_BYTE_BUFFER_DECODER,
+    READONLY_DIRECT_BYTE_BUFFER_DECODER,
+    INPUT_STREAM_DECODER;
+  }
+
+  private static class BinaryDecoder <MessageType extends AbstractMessage> {
+    public MessageType decode (ByteString bytes, BinaryDecoderType type, 
+        Parser <MessageType> parser, ExtensionRegistry extensions)
       throws InvalidProtocolBufferException {
-    TestMessagesProto2.TestAllTypesProto2[] messages =
-        new TestMessagesProto2.TestAllTypesProto2[BinaryDecoder.values().length];
-    InvalidProtocolBufferException[] exceptions =
-        new InvalidProtocolBufferException[BinaryDecoder.values().length];
+      switch (type) {
+        case BTYE_STRING_DECODER: 
+          return parser.parseFrom(bytes, extensions);
+        case BYTE_ARRAY_DECODER:
+          return parser.parseFrom(bytes.toByteArray(), extensions);
+        case ARRAY_BYTE_BUFFER_DECODER: {
+          ByteBuffer buffer = ByteBuffer.allocate(bytes.size());
+          bytes.copyTo(buffer);
+          buffer.flip();
+          try {
+            return parser.parseFrom(CodedInputStream.newInstance(buffer), extensions);
+          } catch (InvalidProtocolBufferException e) {
+            throw e;
+          }
+        }
+        case READONLY_ARRAY_BYTE_BUFFER_DECODER: {
+          try {
+            return parser.parseFrom(
+                CodedInputStream.newInstance(bytes.asReadOnlyByteBuffer()), extensions);
+          } catch (InvalidProtocolBufferException e) {
+            throw e;
+          }
+        } 
+        case DIRECT_BYTE_BUFFER_DECODER: {
+          ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
+          bytes.copyTo(buffer);
+          buffer.flip();
+          try {
+            return parser.parseFrom(CodedInputStream.newInstance(buffer), extensions);
+          } catch (InvalidProtocolBufferException e) {
+            throw e;
+          }
+        }
+        case READONLY_DIRECT_BYTE_BUFFER_DECODER: {
+          ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
+          bytes.copyTo(buffer);
+          buffer.flip();
+          try {
+            return parser.parseFrom(
+                CodedInputStream.newInstance(buffer.asReadOnlyBuffer()), extensions);
+          } catch (InvalidProtocolBufferException e) {
+            throw e;
+          }
+        }
+        case INPUT_STREAM_DECODER: {
+          try {
+            return parser.parseFrom(bytes.newInput(), extensions);
+          } catch (InvalidProtocolBufferException e) {
+            throw e;
+          }
+        }
+        default :
+          return null;
+      }
+    }
+  }
+
+  private <MessageType extends AbstractMessage> MessageType parseBinary(
+      ByteString bytes, Parser <MessageType> parser, ExtensionRegistry extensions)
+      throws InvalidProtocolBufferException {
+    ArrayList <MessageType> messages = new ArrayList <MessageType> ();
+    ArrayList <InvalidProtocolBufferException> exceptions =
+        new ArrayList <InvalidProtocolBufferException>();
+    
+    for (int i = 0; i < BinaryDecoderType.values().length; i++) {
+      messages.add(null);
+      exceptions.add(null);
+    }
+    BinaryDecoder <MessageType> decoder = new BinaryDecoder <MessageType> ();
 
     boolean hasMessage = false;
     boolean hasException = false;
-    for (int i = 0; i < BinaryDecoder.values().length; ++i) {
+    for (int i = 0; i < BinaryDecoderType.values().length; ++i) {
       try {
-        messages[i] = BinaryDecoder.values()[i].parseProto2(bytes);
+        //= BinaryDecoderType.values()[i].parseProto3(bytes);
+        messages.set(i, decoder.decode(bytes, BinaryDecoderType.values()[i], parser, extensions));
         hasMessage = true;
       } catch (InvalidProtocolBufferException e) {
-        exceptions[i] = e;
+        exceptions.set(i, e);
         hasException = true;
       }
     }
@@ -327,9 +157,9 @@
     if (hasMessage && hasException) {
       StringBuilder sb =
           new StringBuilder("Binary decoders disagreed on whether the payload was valid.\n");
-      for (int i = 0; i < BinaryDecoder.values().length; ++i) {
-        sb.append(BinaryDecoder.values()[i].name());
-        if (messages[i] != null) {
+      for (int i = 0; i < BinaryDecoderType.values().length; ++i) {
+        sb.append(BinaryDecoderType.values()[i].name());
+        if (messages.get(i) != null) {
           sb.append(" accepted the payload.\n");
         } else {
           sb.append(" rejected the payload.\n");
@@ -341,14 +171,14 @@
     if (hasException) {
       // We do not check if exceptions are equal. Different implementations may return different
       // exception messages. Throw an arbitrary one out instead.
-      throw exceptions[0];
+      throw exceptions.get(0);
     }
 
     // Fast path comparing all the messages with the first message, assuming equality being
     // symmetric and transitive.
     boolean allEqual = true;
-    for (int i = 1; i < messages.length; ++i) {
-      if (!messages[0].equals(messages[i])) {
+    for (int i = 1; i < messages.size(); ++i) {
+      if (!messages.get(0).equals(messages.get(i))) {
         allEqual = false;
         break;
       }
@@ -357,12 +187,12 @@
     // Slow path: compare and find out all unequal pairs.
     if (!allEqual) {
       StringBuilder sb = new StringBuilder();
-      for (int i = 0; i < messages.length - 1; ++i) {
-        for (int j = i + 1; j < messages.length; ++j) {
-          if (!messages[i].equals(messages[j])) {
-            sb.append(BinaryDecoder.values()[i].name())
+      for (int i = 0; i < messages.size() - 1; ++i) {
+        for (int j = i + 1; j < messages.size(); ++j) {
+          if (!messages.get(i).equals(messages.get(j))) {
+            sb.append(BinaryDecoderType.values()[i].name())
                 .append(" and ")
-                .append(BinaryDecoder.values()[j].name())
+                .append(BinaryDecoderType.values()[j].name())
                 .append(" parsed the payload differently.\n");
           }
         }
@@ -370,25 +200,29 @@
       throw new RuntimeException(sb.toString());
     }
 
-    return messages[0];
+    return messages.get(0);
   }
 
-
   private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
     com.google.protobuf.AbstractMessage testMessage;
-    boolean isProto3 = request.getMessageType().equals("proto3");
+    boolean isProto3 = request.getMessageType().equals("protobuf_test_messages.proto3.TestAllTypes");
+    boolean isProto2 = request.getMessageType().equals("protobuf_test_messages.proto2.TestAllTypesProto2");
 
     switch (request.getPayloadCase()) {
       case PROTOBUF_PAYLOAD: {
         if (isProto3) {
           try {
-            testMessage = parseBinaryToProto3(request.getProtobufPayload());
+            ExtensionRegistry extensions = ExtensionRegistry.newInstance();
+            TestMessagesProto3.registerAllExtensions(extensions);
+            testMessage = parseBinary(request.getProtobufPayload(), TestAllTypes.parser(), extensions);
           } catch (InvalidProtocolBufferException e) {
             return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
           }
-        } else if (request.getMessageType().equals("proto2")) {
+        } else if (isProto2) {
           try {
-            testMessage = parseBinaryToProto2(request.getProtobufPayload());
+            ExtensionRegistry extensions = ExtensionRegistry.newInstance();
+            TestMessagesProto2.registerAllExtensions(extensions);
+            testMessage = parseBinary(request.getProtobufPayload(), TestAllTypesProto2.parser(), extensions);
           } catch (InvalidProtocolBufferException e) {
             return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
           }