public ProtoSchemaGenerator(SerializationContext serializationContext, String fileName, String packageName, Set<Class<?>> classes) { if (fileName == null) { throw new ProtoSchemaBuilderException("fileName cannot be null"); } if (classes.isEmpty()) { throw new ProtoSchemaBuilderException("At least one class must be specified"); } this.serializationContext = serializationContext; this.fileName = fileName; this.packageName = packageName; this.classes = classes; }
private void checkConstructor() { Constructor<?> ctor; try { ctor = javaClass.getDeclaredConstructor(); } catch (NoSuchMethodException e) { throw new ProtoSchemaBuilderException("Class " + javaClass.getCanonicalName() + " must have a non-private no argument constructor"); } if (Modifier.isPrivate(ctor.getModifiers())) { throw new ProtoSchemaBuilderException("Class " + javaClass.getCanonicalName() + " must have a non-private no argument constructor"); } }
ProtoMessageTypeMetadata(ProtoSchemaGenerator protoSchemaGenerator, Class<?> messageClass) { super(getProtoName(messageClass), messageClass); this.protoSchemaGenerator = protoSchemaGenerator; // ensure class is not abstract and has a default public constructor if (Modifier.isAbstract(javaClass.getModifiers())) { throw new ProtoSchemaBuilderException("Abstract classes are not allowed: " + javaClass); } try { javaClass.getDeclaredConstructor(); } catch (NoSuchMethodException e) { throw new ProtoSchemaBuilderException("The class " + javaClass.getCanonicalName() + " must be instantiable using a public no-argument constructor."); } }
private ProtoMessageTypeMetadata findOuterType(Class<?> c) { ProtoTypeMetadata outer = null; Class<?> ec = c.getEnclosingClass(); while (ec != null) { if (ec.isEnum()) { throw new ProtoSchemaBuilderException("Classes defined inside an Enum are not allowed : " + c.getCanonicalName()); } outer = metadataByClass.get(ec); if (outer != null) { break; } ec = ec.getEnclosingClass(); } return (ProtoMessageTypeMetadata) outer; }
private Method findSetter(String propertyName, Class<?> propertyType) { String methodName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); Method setter; try { setter = javaClass.getMethod(methodName, propertyType); } catch (NoSuchMethodException e) { throw new ProtoSchemaBuilderException("No setter method found for property '" + propertyName + "' of type " + propertyType + " in class " + javaClass.getName()); } if (!setter.getReturnType().equals(Void.TYPE)) { throw new ProtoSchemaBuilderException("No suitable setter method found for property '" + propertyName + "' of type " + propertyType + " in class " + javaClass.getName() + ". The candidate method does not have a suitable return type: " + setter); } return setter; }
private Method findGetter(String propertyName, Class<?> propertyType) { String prefix = "get"; if (propertyType.equals(Boolean.TYPE) || propertyType.equals(Boolean.class)) { prefix = "is"; } String methodName = prefix + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); Method getter; try { getter = javaClass.getMethod(methodName); } catch (NoSuchMethodException e) { throw new ProtoSchemaBuilderException("No getter method found for property '" + propertyName + "' of type " + propertyType + " in class " + javaClass.getName()); } if (!getter.getReturnType().equals(propertyType)) { throw new ProtoSchemaBuilderException("No suitable getter method found for property '" + propertyName + "' of type " + propertyType + " in class " + javaClass.getName() + ". The candidate method does not have a suitable return type: " + getter); } return getter; }
throw new ProtoSchemaBuilderException("The collection class of repeated field '" + fieldName + "' of " + clazz + " must implement java.util.Collection."); throw new ProtoSchemaBuilderException("The collection class (" + collectionImplementation.getName() + ") of repeated field '" + fieldName + "' of " + clazz + " must not be abstract. Please specify an appropriate class in collectionImplementation member."); throw new ProtoSchemaBuilderException("The collection class ('" + collectionImplementation.getName() + "') of repeated field '" + fieldName + "' of " + clazz + " must have a public no-argument constructor."); throw new ProtoSchemaBuilderException("The collection implementation class ('" + collectionImplementation.getName() + "') of repeated field '" + fieldName + "' of " + clazz + " is not assignable to this field's type."); throw new ProtoSchemaBuilderException("Specifying the collection implementation class is only allowed for repeated/collection fields: '" + fieldName + "' of " + clazz);
throw new ProtoSchemaBuilderException("Type " + clazz + " is not a valid Date type because it does not have a constructor that accepts a 'long' timestamp parameter");
@Override public void scanMemberAnnotations() { if (fields == null) { // all the fields discovered in this class hierarchy, by number // use a TreeMap to ensure ascending order by field number fields = new TreeMap<>(); // all the fields discovered in this class hierarchy, by name Map<String, ProtoFieldMetadata> fieldsByName = new HashMap<>(); Set<Class<?>> examinedClasses = new HashSet<>(); discoverFields(javaClass, examinedClasses, fields, fieldsByName); if (fields.isEmpty()) { throw new ProtoSchemaBuilderException("Class " + javaClass.getCanonicalName() + " does not have any @ProtoField annotated fields. The class should be either annotated or it should have a custom marshaller."); } checkConstructor(); } }
private void defineType(ProtoTypeMetadata protoTypeMetadata) { String fullName = protoTypeMetadata.getFullName(); ProtoTypeMetadata existing = metadataByTypeName.get(fullName); if (existing != null) { throw new ProtoSchemaBuilderException("Duplicate type definition. Type '" + fullName + "' is defined by " + protoTypeMetadata.getJavaClass().getName() + " and also by " + existing.getJavaClass().getName()); } metadataByTypeName.put(fullName, protoTypeMetadata); metadataByClass.put(protoTypeMetadata.getJavaClass(), protoTypeMetadata); } }
ProtoTypeMetadata m = protoSchemaGenerator.scanAnnotations(javaType); if (!m.isEnum()) { throw new ProtoSchemaBuilderException(javaType + " is not a Protobuf marshallable enum type"); ProtoTypeMetadata m = protoSchemaGenerator.scanAnnotations(javaType); if (m.isEnum()) { throw new ProtoSchemaBuilderException(javaType + " is not a Protobuf marshallable message type"); case ENUM: if (!javaType.isEnum()) { throw new ProtoSchemaBuilderException(javaType + " is not a Protobuf marshallable enum type"); ProtoTypeMetadata m = protoSchemaGenerator.scanAnnotations(javaType); if (m.isEnum()) { throw new ProtoSchemaBuilderException(javaType + " is not a Protobuf marshallable message type"); throw new ProtoSchemaBuilderException("Incompatible types : " + javaType.getName() + " vs " + type); break; case BYTES: if (javaType != byte[].class) throw new ProtoSchemaBuilderException("Incompatible types : " + javaType.getName() + " vs " + type); break; case DOUBLE: if (javaType != Double.class && javaType != Double.TYPE) throw new ProtoSchemaBuilderException("Incompatible types : " + javaType.getName() + " vs " + type); break; case FLOAT: if (javaType != Float.class && javaType != Float.TYPE) throw new ProtoSchemaBuilderException("Incompatible types : " + javaType.getName() + " vs " + type);
ProtoEnumValueMetadata enumVal = protoEnumTypeMetadata.getMemberByName(defaultValue); if (enumVal == null) { throw new ProtoSchemaBuilderException("Invalid default value for field '" + fieldName + "' of type " + fieldType.getName() + " of class " + clazz.getName() + ": " + defaultValue + " is not a member of " + protoEnumTypeMetadata.getFullName()); throw new ProtoSchemaBuilderException("Invalid default value for field '" + fieldName + "' of type " + fieldType.getName() + " of class " + clazz.getName() + ": " + defaultValue); throw new ProtoSchemaBuilderException("Invalid default value for field '" + fieldName + "' of type " + fieldType.getName() + " of class " + clazz.getName() + ": " + defaultValue, e); throw new ProtoSchemaBuilderException("No default value is allowed for field '" + fieldName + "' of " + clazz);
ProtoEnumValue annotation = f.getAnnotation(ProtoEnumValue.class); if (annotation == null) { throw new ProtoSchemaBuilderException("Enum members must have the @ProtoEnumValue annotation: " + javaClass.getName() + '.' + f.getName()); throw new ProtoSchemaBuilderException("Found duplicate definition of Protobuf enum tag " + annotation.number() + " on annotation member: " + javaClass.getName() + '.' + f.getName()); throw new ProtoSchemaBuilderException("Members of enum " + javaClass.getCanonicalName() + " must be @ProtoEnum annotated");
if (field.getAnnotation(ProtoUnknownFieldSet.class) != null) { if (unknownFieldSetField != null || unknownFieldSetGetter != null || unknownFieldSetSetter != null) { throw new ProtoSchemaBuilderException("The @ProtoUnknownFieldSet annotation should not be used multiple times in one class hierarchy : " + field); if (annotation != null) { if (Modifier.isStatic(field.getModifiers())) { throw new ProtoSchemaBuilderException("Static fields cannot be @ProtoField annotated: " + field); throw new ProtoSchemaBuilderException("Final fields cannot be @ProtoField annotated: " + field); throw new ProtoSchemaBuilderException("Private fields cannot be @ProtoField annotated: " + field); throw new ProtoSchemaBuilderException("0 is not a valid Protobuf field number: " + field); boolean isRequired = annotation.required(); if (isRepeated && isRequired) { throw new ProtoSchemaBuilderException("Repeated field '" + fieldName + "' of " + clazz + " cannot be marked required."); throw new ProtoSchemaBuilderException("The type " + javaType.getName() + " of field '" + fieldName + "' of " + clazz + " should not be abstract."); throw new ProtoSchemaBuilderException("Primitive field '" + fieldName + "' of " + clazz + " should be marked required or should have a default value."); throw new ProtoSchemaBuilderException("Duplicate field number definition. Found two field definitions with number " + annotation.number() + ": in " + fieldMetadata.getLocation() + " and in " + existing.getLocation()); throw new ProtoSchemaBuilderException("Duplicate field name definition. Found two field definitions with name '" + fieldMetadata.getName() + "': in " + fieldMetadata.getLocation() + " and in " + existing.getLocation()); if (method.getAnnotation(ProtoUnknownFieldSet.class) != null) {
generateMarshallers(); } catch (Exception e) { throw new ProtoSchemaBuilderException("Failed to generate marshaller implementation class", e);