Search in sources :

Example 1 with JavaType

use of org.infinispan.protostream.descriptors.JavaType in project protostream by infinispan.

the class ProtoStreamReaderImpl method readPrimitive.

private Object readPrimitive(String fieldName, JavaType javaType) throws IOException {
    final FieldDescriptor fd = messageContext.getFieldByName(fieldName);
    final Type type = fd.getType();
    if (type == Type.ENUM || type == Type.GROUP || type == Type.MESSAGE) {
        throw new IllegalArgumentException("Declared field type is not a primitive : " + fd.getFullName());
    }
    if (fd.getJavaType() != javaType) {
        throw new IllegalArgumentException("Declared field type is not of the expected type : " + fd.getFullName());
    }
    checkFieldRead(fd, false);
    final int expectedTag = fd.getWireTag();
    Object o = messageContext.unknownFieldSet.consumeTag(expectedTag);
    if (o != null) {
        return convertWireTypeToJavaType(type, o);
    }
    TagReader in = messageContext.in;
    while (true) {
        int tag = in.readTag();
        if (tag == 0) {
            break;
        }
        if (tag == expectedTag) {
            switch(type) {
                case DOUBLE:
                    return in.readDouble();
                case FLOAT:
                    return in.readFloat();
                case BOOL:
                    return in.readBool();
                case STRING:
                    return in.readString();
                case BYTES:
                    return in.readByteArray();
                case INT32:
                    return in.readInt32();
                case SFIXED32:
                    return in.readSFixed32();
                case FIXED32:
                    return in.readFixed32();
                case UINT32:
                    return in.readUInt32();
                case SINT32:
                    return in.readSInt32();
                case INT64:
                    return in.readInt64();
                case UINT64:
                    return in.readUInt64();
                case FIXED64:
                    return in.readFixed64();
                case SFIXED64:
                    return in.readSFixed64();
                case SINT64:
                    return in.readSInt64();
                default:
                    throw new IOException("Unexpected field type : " + type);
            }
        }
        messageContext.unknownFieldSet.readSingleField(tag, in);
    }
    if (fd.hasDefaultValue()) {
        return fd.getDefaultValue();
    }
    if (fd.isRequired()) {
        throw new IOException("Field " + fd.getFullName() + " is required but is not present in the stream");
    }
    return null;
}
Also used : Type(org.infinispan.protostream.descriptors.Type) WireType(org.infinispan.protostream.descriptors.WireType) JavaType(org.infinispan.protostream.descriptors.JavaType) IOException(java.io.IOException) FieldDescriptor(org.infinispan.protostream.descriptors.FieldDescriptor) TagReader(org.infinispan.protostream.TagReader)

Example 2 with JavaType

use of org.infinispan.protostream.descriptors.JavaType 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);
            }
        }
    }
}
Also used : Optional(java.util.Optional) ProtoField(org.infinispan.protostream.annotations.ProtoField) ArrayList(java.util.ArrayList) XClass(org.infinispan.protostream.annotations.impl.types.XClass) ProtoUnknownFieldSet(org.infinispan.protostream.annotations.ProtoUnknownFieldSet) Type(org.infinispan.protostream.descriptors.Type) JavaType(org.infinispan.protostream.descriptors.JavaType) ProtoSchemaBuilderException(org.infinispan.protostream.annotations.ProtoSchemaBuilderException) XField(org.infinispan.protostream.annotations.impl.types.XField) XMethod(org.infinispan.protostream.annotations.impl.types.XMethod)

Aggregations

JavaType (org.infinispan.protostream.descriptors.JavaType)2 Type (org.infinispan.protostream.descriptors.Type)2 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 Optional (java.util.Optional)1 TagReader (org.infinispan.protostream.TagReader)1 ProtoField (org.infinispan.protostream.annotations.ProtoField)1 ProtoSchemaBuilderException (org.infinispan.protostream.annotations.ProtoSchemaBuilderException)1 ProtoUnknownFieldSet (org.infinispan.protostream.annotations.ProtoUnknownFieldSet)1 XClass (org.infinispan.protostream.annotations.impl.types.XClass)1 XField (org.infinispan.protostream.annotations.impl.types.XField)1 XMethod (org.infinispan.protostream.annotations.impl.types.XMethod)1 FieldDescriptor (org.infinispan.protostream.descriptors.FieldDescriptor)1 WireType (org.infinispan.protostream.descriptors.WireType)1