use of org.infinispan.protostream.annotations.ProtoSchemaBuilderException in project protostream by infinispan.
the class ProtoMessageTypeMetadata method discoverFields.
private void discoverFields(XClass clazz, Set<XClass> examinedClasses) {
if (!examinedClasses.add(clazz)) {
// avoid re-examining classes due to multiple interface inheritance
return;
}
if (clazz.getSuperclass() != null) {
discoverFields(clazz.getSuperclass(), examinedClasses);
}
for (XClass i : clazz.getInterfaces()) {
discoverFields(i, examinedClasses);
}
for (XField field : clazz.getDeclaredFields()) {
if (field.getAnnotation(ProtoUnknownFieldSet.class) != null) {
if (isAdapter) {
throw new ProtoSchemaBuilderException("No ProtoStream annotations should be present on fields when @ProtoAdapter is present on a class : " + clazz.getCanonicalName() + '.' + field);
}
if (unknownFieldSetField != null || unknownFieldSetGetter != null || unknownFieldSetSetter != null) {
throw new ProtoSchemaBuilderException("The @ProtoUnknownFieldSet annotation should not occur more than once in a class and its superclasses and superinterfaces : " + clazz.getCanonicalName() + '.' + field);
}
unknownFieldSetField = field;
} else {
ProtoField annotation = field.getAnnotation(ProtoField.class);
if (annotation != null) {
if (isAdapter) {
throw new ProtoSchemaBuilderException("No ProtoStream annotations should be present on fields when @ProtoAdapter is present on a class : " + clazz.getCanonicalName() + '.' + field);
}
if (field.isStatic()) {
throw new ProtoSchemaBuilderException("Static fields cannot be @ProtoField annotated: " + clazz.getCanonicalName() + '.' + field);
}
if (factory == null && field.isFinal()) {
// todo [anistor] maybe allow this
throw new ProtoSchemaBuilderException("Final fields cannot be @ProtoField annotated: " + clazz.getCanonicalName() + '.' + field);
}
if (field.isPrivate()) {
throw new ProtoSchemaBuilderException("Private fields cannot be @ProtoField annotated: " + clazz.getCanonicalName() + '.' + field);
}
int number = getNumber(annotation, field);
String fieldName = annotation.name();
if (fieldName.isEmpty()) {
fieldName = field.getName();
}
Type protobufType = annotation.type();
if (field.getType() == typeFactory.fromClass(byte[].class) && protobufType == Type.MESSAGE) {
// MESSAGE is the default and stands for 'undefined', we can override it with a better default
protobufType = Type.BYTES;
}
boolean isArray = isArray(field.getType(), protobufType);
boolean isRepeated = isRepeated(field.getType(), protobufType);
boolean isRequired = annotation.required();
if (isRepeated && isRequired) {
throw new ProtoSchemaBuilderException("Repeated field '" + fieldName + "' of " + clazz.getCanonicalName() + " cannot be marked required.");
}
XClass javaType = getJavaTypeFromAnnotation(annotation);
if (javaType == typeFactory.fromClass(void.class)) {
javaType = isRepeated ? field.determineRepeatedElementType() : field.getType();
}
if (javaType == typeFactory.fromClass(byte[].class) && protobufType == Type.MESSAGE) {
// MESSAGE is the default and stands for 'undefined', we can override it with a better default
protobufType = Type.BYTES;
}
if (!javaType.isArray() && !javaType.isPrimitive() && javaType.isAbstract() && !javaType.isEnum()) {
throw new ProtoSchemaBuilderException("The type " + javaType.getCanonicalName() + " of field '" + fieldName + "' of " + clazz.getCanonicalName() + " should not be abstract.");
}
protobufType = getProtobufType(javaType, protobufType);
Object defaultValue = getDefaultValue(clazz, fieldName, javaType, protobufType, annotation.defaultValue());
if (!isRequired && !isRepeated && javaType.isPrimitive() && defaultValue == null) {
throw new ProtoSchemaBuilderException("Primitive field '" + fieldName + "' of " + clazz.getCanonicalName() + " is not nullable so it should be either marked required or should have a default value.");
}
XClass collectionImplementation = getCollectionImplementation(clazz, field.getType(), getCollectionImplementationFromAnnotation(annotation), fieldName, isRepeated);
if (isArray) {
collectionImplementation = typeFactory.fromClass(ArrayList.class);
}
ProtoTypeMetadata protoTypeMetadata = null;
if (protobufType.getJavaType() == JavaType.ENUM || protobufType.getJavaType() == JavaType.MESSAGE) {
protoTypeMetadata = protoSchemaGenerator.scanAnnotations(javaType);
}
ProtoFieldMetadata fieldMetadata = new ProtoFieldMetadata(number, fieldName, javaType, collectionImplementation, protobufType, protoTypeMetadata, isRequired, isRepeated, isArray, defaultValue, field);
ProtoFieldMetadata existing = fieldsByNumber.get(number);
if (existing != null) {
throw new ProtoSchemaBuilderException("Duplicate field number definition. Found two field definitions with number " + number + ": in " + fieldMetadata.getLocation() + " and in " + existing.getLocation());
}
existing = fieldsByName.get(fieldMetadata.getName());
if (existing != null) {
throw new ProtoSchemaBuilderException("Duplicate field name definition. Found two field definitions with name '" + fieldMetadata.getName() + "': in " + fieldMetadata.getLocation() + " and in " + existing.getLocation());
}
checkReserved(fieldMetadata);
fieldsByNumber.put(fieldMetadata.getNumber(), fieldMetadata);
fieldsByName.put(fieldName, fieldMetadata);
}
}
}
for (XMethod method : clazz.getDeclaredMethods()) {
if (method.getAnnotation(ProtoUnknownFieldSet.class) != null) {
if (unknownFieldSetField != null || unknownFieldSetGetter != null || unknownFieldSetSetter != null) {
throw new ProtoSchemaBuilderException("The @ProtoUnknownFieldSet annotation should not occur more than once in a class and its superclasses and superinterfaces : " + method);
}
String propertyName;
if (method.getReturnType() == typeFactory.fromClass(void.class)) {
// this method is expected to be a setter
if (method.getName().startsWith("set") && method.getName().length() > 3) {
propertyName = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
} else {
throw new ProtoSchemaBuilderException("Illegal setter method signature: " + method);
}
if (isAdapter && method.getParameterTypes().length != 2 || !isAdapter && method.getParameterTypes().length != 1) {
throw new ProtoSchemaBuilderException("Illegal setter method signature: " + method);
}
// TODO [anistor] also check setter args
unknownFieldSetSetter = method;
unknownFieldSetGetter = findGetter(propertyName, method.getParameterTypes()[0]);
} else {
// this method is expected to be a getter
if (method.getName().startsWith("get") && method.getName().length() > 3) {
propertyName = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
} else if (method.getName().startsWith("is") && method.getName().length() > 2) {
propertyName = Character.toLowerCase(method.getName().charAt(2)) + method.getName().substring(3);
} else {
throw new ProtoSchemaBuilderException("Illegal getter method signature: " + method);
}
if (isAdapter && method.getParameterTypes().length != 1 || !isAdapter && method.getParameterTypes().length != 0) {
throw new ProtoSchemaBuilderException("Illegal getter method signature: " + method);
}
// TODO [anistor] also check getter args
unknownFieldSetGetter = method;
unknownFieldSetSetter = findSetter(propertyName, unknownFieldSetGetter.getReturnType());
}
} else {
ProtoField annotation = method.getAnnotation(ProtoField.class);
if (annotation != null) {
if (method.isPrivate()) {
throw new ProtoSchemaBuilderException("Private methods cannot be @ProtoField annotated: " + method);
}
if (!isAdapter && method.isStatic()) {
throw new ProtoSchemaBuilderException("Static methods cannot be @ProtoField annotated: " + method);
}
String propertyName;
XMethod getter;
XMethod setter;
XClass getterReturnType;
// we can have the annotation present on either getter or setter but not both
if (method.getReturnType() == typeFactory.fromClass(void.class)) {
// this method is expected to be a setter
if (method.getName().startsWith("set") && method.getName().length() >= 4) {
propertyName = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
} else {
// not a standard java-beans setter, use the whole name as property name
propertyName = method.getName();
}
if (isAdapter && method.getParameterTypes().length != 2 || !isAdapter && method.getParameterTypes().length != 1) {
throw new ProtoSchemaBuilderException("Illegal setter method signature: " + method);
}
// TODO [anistor] also check setter args
setter = method;
getter = findGetter(propertyName, method.getParameterTypes()[0]);
getterReturnType = getter.getReturnType();
if (getterReturnType == typeFactory.fromClass(Optional.class)) {
getterReturnType = getter.determineOptionalReturnType();
}
} else {
// this method is expected to be a getter
if (method.getName().startsWith("get") && method.getName().length() >= 4) {
propertyName = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
} else if (method.getName().startsWith("is") && method.getName().length() >= 3) {
propertyName = Character.toLowerCase(method.getName().charAt(2)) + method.getName().substring(3);
} else {
// not a standard java-beans getter
propertyName = method.getName();
}
if (isAdapter && method.getParameterTypes().length != 1 || !isAdapter && method.getParameterTypes().length != 0) {
throw new ProtoSchemaBuilderException("Illegal setter method signature: " + method);
}
// TODO [anistor] also check getter args
getter = method;
getterReturnType = getter.getReturnType();
if (getterReturnType == typeFactory.fromClass(Optional.class)) {
getterReturnType = getter.determineOptionalReturnType();
}
setter = factory == null ? findSetter(propertyName, getterReturnType) : null;
}
int number = getNumber(annotation, method);
String fieldName = annotation.name();
if (fieldName.isEmpty()) {
fieldName = propertyName;
}
Type protobufType = annotation.type();
if (getterReturnType == typeFactory.fromClass(byte[].class) && protobufType == Type.MESSAGE) {
// MESSAGE is the default and stands for 'undefined', we can override it with a better default
protobufType = Type.BYTES;
}
boolean isArray = isArray(getterReturnType, protobufType);
boolean isRepeated = isRepeated(getterReturnType, protobufType);
boolean isRequired = annotation.required();
if (isRepeated && isRequired) {
throw new ProtoSchemaBuilderException("Repeated field '" + fieldName + "' of " + clazz.getCanonicalName() + " cannot be marked required.");
}
XClass javaType = getJavaTypeFromAnnotation(annotation);
if (javaType == typeFactory.fromClass(void.class)) {
javaType = isRepeated ? getter.determineRepeatedElementType() : getterReturnType;
}
if (javaType == typeFactory.fromClass(byte[].class) && protobufType == Type.MESSAGE) {
// MESSAGE is the default and stands for 'undefined', we can override it with a better default
protobufType = Type.BYTES;
}
if (!javaType.isArray() && !javaType.isPrimitive() && javaType.isAbstract() && !javaType.isEnum()) {
throw new ProtoSchemaBuilderException("The type " + javaType.getCanonicalName() + " of field '" + fieldName + "' of " + clazz.getCanonicalName() + " should not be abstract.");
}
protobufType = getProtobufType(javaType, protobufType);
Object defaultValue = getDefaultValue(clazz, fieldName, javaType, protobufType, annotation.defaultValue());
if (!isRequired && !isRepeated && javaType.isPrimitive() && defaultValue == null) {
throw new ProtoSchemaBuilderException("Primitive field '" + fieldName + "' of " + clazz.getCanonicalName() + " is not nullable so it should be either marked required or should have a default value.");
}
XClass collectionImplementation = getCollectionImplementation(clazz, getterReturnType, getCollectionImplementationFromAnnotation(annotation), fieldName, isRepeated);
if (isArray) {
collectionImplementation = typeFactory.fromClass(ArrayList.class);
}
ProtoTypeMetadata protoTypeMetadata = null;
if (protobufType.getJavaType() == JavaType.ENUM || protobufType.getJavaType() == JavaType.MESSAGE) {
protoTypeMetadata = protoSchemaGenerator.scanAnnotations(javaType);
}
ProtoFieldMetadata fieldMetadata = new ProtoFieldMetadata(number, fieldName, javaType, collectionImplementation, protobufType, protoTypeMetadata, isRequired, isRepeated, isArray, defaultValue, propertyName, method, getter, setter);
ProtoFieldMetadata existing = fieldsByNumber.get(number);
if (existing != null) {
throw new ProtoSchemaBuilderException("Duplicate field definition. Found two field definitions with number " + number + ": in " + fieldMetadata.getLocation() + " and in " + existing.getLocation());
}
existing = fieldsByName.get(fieldMetadata.getName());
if (existing != null) {
throw new ProtoSchemaBuilderException("Duplicate field definition. Found two field definitions with name '" + fieldMetadata.getName() + "': in " + fieldMetadata.getLocation() + " and in " + existing.getLocation());
}
checkReserved(fieldMetadata);
fieldsByNumber.put(number, fieldMetadata);
fieldsByName.put(fieldName, fieldMetadata);
}
}
}
}
use of org.infinispan.protostream.annotations.ProtoSchemaBuilderException in project protostream by infinispan.
the class ReservedProcessor method scanReserved.
private void scanReserved(XClass clazz, Set<XClass> processedClasses) {
if (!processedClasses.add(clazz)) {
// avoid re-processing classes due to multiple interface inheritance
return;
}
if (clazz.getSuperclass() != null) {
scanReserved(clazz.getSuperclass(), processedClasses);
}
for (XClass i : clazz.getInterfaces()) {
scanReserved(i, processedClasses);
}
for (ProtoReserved reserved : clazz.getAnnotationsByType(ProtoReserved.class)) {
int[] numbers = reserved.numbers();
if (numbers.length == 0) {
numbers = reserved.value();
} else if (reserved.value().length > 0) {
throw new ProtoSchemaBuilderException("@ProtoReserved annotation must not specify both 'value' and 'numbers' : " + clazz.getCanonicalName());
}
for (int number : numbers) {
ReservedInterval i = new ReservedInterval(clazz, number);
ReservedInterval dup = i.findOverlap(reservedNumbers);
if (dup != null) {
if (dup.where.equals(clazz)) {
throw new ProtoSchemaBuilderException("Found duplicate @ProtoReserved number " + number + " in " + clazz.getCanonicalName());
} else {
throw new ProtoSchemaBuilderException("@ProtoReserved number " + number + " in " + clazz.getCanonicalName() + " conflicts with @ProtoReserved in " + dup.where.getCanonicalName());
}
}
reservedNumbers.add(i);
}
for (ProtoReserved.Range range : reserved.ranges()) {
ReservedInterval i = new ReservedInterval(clazz, range.from(), range.to());
ReservedInterval dup = i.findOverlap(reservedNumbers);
if (dup != null) {
if (dup.where.equals(clazz)) {
throw new ProtoSchemaBuilderException("Found overlapping @ProtoReserved range \"" + i + "\" in " + clazz.getCanonicalName());
} else {
throw new ProtoSchemaBuilderException("@ProtoReserved range \"" + i + "\" in " + clazz.getCanonicalName() + " conflicts with @ProtoReserved in " + dup.where.getCanonicalName());
}
}
reservedNumbers.add(i);
}
for (String name : reserved.names()) {
if (name.isEmpty()) {
throw new ProtoSchemaBuilderException("@ProtoReserved name cannot be empty: " + clazz.getCanonicalName());
}
XClass dup = reservedNames.put(name, clazz);
if (dup != null) {
if (dup.equals(clazz)) {
throw new ProtoSchemaBuilderException("Found duplicate @ProtoReserved name \"" + name + "\" in " + clazz.getCanonicalName());
} else {
throw new ProtoSchemaBuilderException("@ProtoReserved name \"" + name + "\" in " + clazz.getCanonicalName() + " conflicts with @ProtoReserved name in " + dup.getCanonicalName());
}
}
}
}
}
use of org.infinispan.protostream.annotations.ProtoSchemaBuilderException in project protostream by infinispan.
the class AutoProtoSchemaBuilderAnnotationProcessor method process.
// todo [anistor] check RoundEnvironment.errorRaised() and do not write any more output files if errors are present
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (isDebugEnabled) {
logDebug("AutoProtoSchemaBuilderAnnotationProcessor annotations=%s, rootElements=%s", annotations, roundEnv.getRootElements());
}
Optional<? extends TypeElement> claimedAnnotation = annotations.stream().filter(a -> a.getQualifiedName().contentEquals(ANNOTATION_NAME)).findAny();
try {
if (claimedAnnotation.isPresent()) {
for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(claimedAnnotation.get())) {
AutoProtoSchemaBuilder builderAnnotation = getBuilderAnnotation(annotatedElement);
SerializationContext serCtx = ProtobufUtil.newSerializationContext();
try {
processElement(roundEnv, serCtx, annotatedElement, builderAnnotation, new ProcessorContext());
} catch (ProtoSchemaBuilderException | DescriptorParserException e) {
throw new AnnotationProcessingException(e, annotatedElement, "%s", getStackTraceAsString(e));
}
}
}
if (roundEnv.processingOver()) {
serviceLoaderFileGenerator.writeServiceFile(filer);
}
} catch (AnnotationProcessingException e) {
// this is caused by the user supplying incorrect data in the annotation or related classes
if (isDebugEnabled) {
logDebug("@AutoProtoSchemaBuilder processor threw an exception: %s", getStackTraceAsString(e));
}
reportError(e);
} catch (Exception e) {
// this may be a fatal programming error in the annotation processor itself
reportError(null, "@AutoProtoSchemaBuilder processor threw a fatal exception: %s", getStackTraceAsString(e));
}
return claimedAnnotation.isPresent();
}
Aggregations