CoderRegistry { @VisibleForTesting static <T, CoderT extends Coder<T>, CandidateT> void verifyCompatible( CoderT coder, Type candidateType) throws IncompatibleCoderException { @SuppressWarnings("unchecked") Class<CoderT> coderClass = (Class<CoderT>) coder.getClass(); TypeDescriptor<CoderT> coderDescriptor = TypeDescriptor.of(coderClass); @SuppressWarnings("unchecked") TypeDescriptor<T> codedDescriptor = CoderUtils.getCodedType(coderDescriptor); @SuppressWarnings("unchecked") Class<T> codedClass = (Class<T>) codedDescriptor.getRawType(); Type codedType = codedDescriptor.getType(); @SuppressWarnings("unchecked") TypeDescriptor<CandidateT> candidateDescriptor = (TypeDescriptor<CandidateT>) TypeDescriptor.of(candidateType); @SuppressWarnings("unchecked") Class<CandidateT> candidateClass = (Class<CandidateT>) candidateDescriptor.getRawType(); if (candidateType instanceof TypeVariable) { return; } if (!codedClass.isAssignableFrom(candidateClass)) { throw new IncompatibleCoderException( String.format( "Cannot encode elements of type %s with coder %s because the" + " coded type %s is not assignable from %s", candidateType, coder, codedClass, candidateType), coder, candidateType); } @SuppressWarnings("unchecked") TypeDescriptor<T> candidateOkDescriptor = (TypeDescriptor<T>) candidateDescriptor; if ((codedType instanceof ParameterizedType) && !isNullOrEmpty(coder.getCoderArguments())) { ParameterizedType parameterizedSupertype = (ParameterizedType) candidateOkDescriptor.getSupertype(codedClass).getType(); Type[] typeArguments = parameterizedSupertype.getActualTypeArguments(); List<? extends Coder<?>> typeArgumentCoders = coder.getCoderArguments(); if (typeArguments.length < typeArgumentCoders.size()) { throw new IncompatibleCoderException( String.format( "Cannot encode elements of type %s with coder %s:" + " the generic supertype %s has %s type parameters, which is less than the" + " number of coder arguments %s has (%s).", candidateOkDescriptor, coder, parameterizedSupertype, typeArguments.length, coder, typeArgumentCoders.size()), coder, candidateOkDescriptor.getType()); } for (int i = 0; i < typeArgumentCoders.size(); i++) { try { Coder<?> typeArgumentCoder = typeArgumentCoders.get(i); verifyCompatible( typeArgumentCoder, candidateDescriptor.resolveType(typeArguments[i]).getType()); } catch (IncompatibleCoderException exn) { throw new IncompatibleCoderException( String.format( "Cannot encode elements of type %s with coder %s" + " because some component coder is incompatible", candidateType, coder), coder, candidateType, exn); } } } } private  CoderRegistry(); static CoderRegistry createDefault(); void registerCoderProvider(CoderProvider coderProvider); void registerCoderForClass(Class<?> clazz, Coder<?> coder); void registerCoderForType(TypeDescriptor<?> type, Coder<?> coder); Coder<T> getCoder(Class<T> clazz); Coder<T> getCoder(TypeDescriptor<T> type); @Deprecated @Internal Coder<OutputT> getCoder(
      TypeDescriptor<OutputT> typeDescriptor,
      TypeDescriptor<InputT> inputTypeDescriptor,
      Coder<InputT> inputCoder); @Deprecated @Internal Coder<OutputT> getOutputCoder(
      SerializableFunction<InputT, OutputT> fn, Coder<InputT> inputCoder); @Deprecated @Internal Coder<OutputT> getCoder(
      Class<? extends T> subClass,
      Class<T> baseClass,
      Map<Type, ? extends Coder<?>> knownCoders,
      TypeVariable<?> param);  }
@Test public void testTypeCompatibility() throws Exception { CoderRegistry.verifyCompatible(BigEndianIntegerCoder.of(), Integer.class); CoderRegistry.verifyCompatible( ListCoder.of(BigEndianIntegerCoder.of()), new TypeDescriptor<List<Integer>>() {}.getType()); }
@Test public void testIntVersusStringIncompatibility() throws Exception { thrown.expect(IncompatibleCoderException.class); thrown.expectMessage("not assignable"); CoderRegistry.verifyCompatible(BigEndianIntegerCoder.of(), String.class); }
@Test public void testTooManyCoderArguments() throws Exception { thrown.expect(IncompatibleCoderException.class); thrown.expectMessage("type parameters"); thrown.expectMessage("less than the number of coder arguments"); CoderRegistry.verifyCompatible( new TooManyComponentCoders<>(BigEndianIntegerCoder.of()), List.class); }
@Test public void testComponentIncompatibility() throws Exception { thrown.expect(IncompatibleCoderException.class); thrown.expectMessage("component coder is incompatible"); CoderRegistry.verifyCompatible( ListCoder.of(BigEndianIntegerCoder.of()), new TypeDescriptor<List<String>>() {}.getType()); }