Class<?> builder = Class.forName(
kvClass.getName() + "$Builder", true, kvClass.getClassLoader());
if (!Builder.class.isAssignableFrom(builder)) {
// The builder class does not extend KeyVersion.Builder
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.BAD_PARENT);
} else if (!kvClass.isAssignableFrom(
builder.getMethod("build").getReturnType())) {
// There is no build() method returning the key version type
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.BAD_BUILD);
}
// The following constructor extraction is reflectively type checked
@SuppressWarnings("unchecked")
Constructor<? extends Builder> constructor =
(Constructor<? extends Builder>)builder.getDeclaredConstructor();
// Constructor can only throw Errors or RuntimeExceptions
for (Class<?> exClass : constructor.getExceptionTypes()) {
if (!RuntimeException.class.isAssignableFrom(exClass)
&& !Error.class.isAssignableFrom(exClass)) {
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.ILLEGAL_THROWS);
}
}
// Check that the builder can instantiate (should not be much overhead)
constructor.newInstance();
builderConstructor = constructor;
} catch (ClassNotFoundException ex) {
// The builder class was not found
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.NO_BUILDER);
} catch (NoSuchMethodException ex) {
// This exception should only be thrown by the constructor check
// (and not the build method check).
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.NO_CONSTRUCTOR);
} catch (ReflectiveOperationException ex) {
// Builder instantiation test failed
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.INSTANTIATE_FAIL);
}
// Check the info annotation
info = kvClass.getAnnotation(KeyVersionInfo.class);
if (info == null) {
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.NO_METADATA);
}
// What we really need is the static registerAllExtensions() method on the
// generated proto. We cannot verify that the proto really belongs to
// the key version (or that it really is a generated proto).
try {
registerProtoExtensions = info.proto()
.getMethod("registerAllExtensions", ExtensionRegistry.class);
if (!Modifier.isStatic(registerProtoExtensions.getModifiers())) {
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.BAD_PROTO);
}
} catch (NoSuchMethodException ex) {
throw new KeyVersionException(
kvClass, KeyVersionException.Reason.BAD_PROTO);
}
}