Search in sources :

Example 1 with Type

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

the class AbstractSchemaJdbcStore method recursiveUpdateParameters.

void recursiveUpdateParameters(Descriptor descriptor, Map<String, Parameter> parameterMap, String[] nestedMessageNames, Set<String> seenNames, boolean key) {
    for (FieldDescriptor fieldDescriptor : descriptor.getFields()) {
        String name = fieldDescriptor.getName();
        if (fieldDescriptor.isRepeated()) {
            throw log.repeatedFieldsNotSupported(name, fieldDescriptor.getTypeName());
        }
        Descriptor fieldMessageDescriptor = fieldDescriptor.getMessageType();
        if (fieldMessageDescriptor != null) {
            String[] newNestedMessageNames;
            if (nestedMessageNames == null) {
                newNestedMessageNames = new String[1];
                newNestedMessageNames[0] = name;
            } else {
                newNestedMessageNames = Arrays.copyOf(nestedMessageNames, nestedMessageNames.length + 1);
                newNestedMessageNames[nestedMessageNames.length] = name;
            }
            recursiveUpdateParameters(fieldMessageDescriptor, parameterMap, newNestedMessageNames, seenNames, key);
            continue;
        }
        if (!seenNames.add(name)) {
            throw log.duplicateFieldInSchema(name, fieldDescriptor.getTypeName());
        }
        Parameter parameter = parameterMap.get(name.toUpperCase());
        if (parameter == null) {
            if (fieldDescriptor.isRequired()) {
                throw log.requiredSchemaFieldNotPresent(name, fieldDescriptor.getTypeName());
            }
            continue;
        }
        if (parameter.primaryIdentifier && !key && !config.getSchemaJdbcConfiguration().embeddedKey()) {
            throw log.primaryKeyPresentButNotEmbedded(parameter.name, fieldDescriptor.getTypeName());
        }
        Function<Json, Json> retrievalFunction;
        BiConsumer<Json, Object> valueConsumer;
        // Oracle doesn't have a boolean type, so use a number of 0 or 1 instead
        if (parameter.type == ProtostreamFieldType.INT_32 && fieldDescriptor.getType() == Type.BOOL) {
            retrievalFunction = json -> Json.factory().number(json.at(name).asBoolean() ? 1 : 0);
            valueConsumer = (json, o) -> json.set(name, ((Integer) o) == 1);
        } else {
            retrievalFunction = json -> json.at(name);
            valueConsumer = (json, o) -> json.set(name, o);
        }
        if (nestedMessageNames == null) {
            updateUnwrap(parameter, key, retrievalFunction);
            parameter.jsonUpdateConsumer = valueConsumer;
        } else {
            updateUnwrap(parameter, key, json -> {
                for (String nestedName : nestedMessageNames) {
                    json = json.at(nestedName);
                    if (json == null)
                        return null;
                }
                return retrievalFunction.apply(json);
            });
            parameter.jsonUpdateConsumer = ((json, o) -> {
                Json nestedJSon = json;
                for (String nestedName : nestedMessageNames) {
                    nestedJSon = json.at(nestedName);
                    if (nestedJSon == null) {
                        nestedJSon = Json.object();
                        json.set(nestedName, nestedJSon);
                    }
                    json = nestedJSon;
                }
                valueConsumer.accept(nestedJSon, o);
            });
        }
    }
}
Also used : Type(org.infinispan.protostream.descriptors.Type) Arrays(java.util.Arrays) ImmutableSerializationContext(org.infinispan.protostream.ImmutableSerializationContext) TableOperations(org.infinispan.persistence.jdbc.common.TableOperations) AbstractSchemaJdbcConfiguration(org.infinispan.persistence.sql.configuration.AbstractSchemaJdbcConfiguration) MarshallableEntryFactory(org.infinispan.persistence.spi.MarshallableEntryFactory) HashMap(java.util.HashMap) ComponentRegistry(org.infinispan.factories.ComponentRegistry) Descriptor(org.infinispan.protostream.descriptors.Descriptor) Function(java.util.function.Function) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) EnumDescriptor(org.infinispan.protostream.descriptors.EnumDescriptor) SQLException(java.sql.SQLException) MediaType(org.infinispan.commons.dataconversion.MediaType) AdvancedCache(org.infinispan.AdvancedCache) ResultSet(java.sql.ResultSet) Map(java.util.Map) BiConsumer(java.util.function.BiConsumer) MarshallableEntry(org.infinispan.persistence.spi.MarshallableEntry) SerializationContextRegistry(org.infinispan.marshall.protostream.impl.SerializationContextRegistry) BaseJdbcStore(org.infinispan.persistence.jdbc.common.impl.BaseJdbcStore) BaseTableOperations(org.infinispan.persistence.jdbc.common.sql.BaseTableOperations) Predicate(java.util.function.Predicate) CacheConfigurationException(org.infinispan.commons.CacheConfigurationException) Timestamp(java.sql.Timestamp) Set(java.util.Set) Json(org.infinispan.commons.dataconversion.internal.Json) PreparedStatement(java.sql.PreparedStatement) Collectors(java.util.stream.Collectors) SchemaJdbcConfiguration(org.infinispan.persistence.sql.configuration.SchemaJdbcConfiguration) FieldDescriptor(org.infinispan.protostream.descriptors.FieldDescriptor) Objects(java.util.Objects) GenericDescriptor(org.infinispan.protostream.descriptors.GenericDescriptor) Base64(java.util.Base64) List(java.util.List) ConnectionFactory(org.infinispan.persistence.jdbc.common.connectionfactory.ConnectionFactory) InitializationContext(org.infinispan.persistence.spi.InitializationContext) DataConversion(org.infinispan.encoding.DataConversion) Types(java.sql.Types) Descriptor(org.infinispan.protostream.descriptors.Descriptor) EnumDescriptor(org.infinispan.protostream.descriptors.EnumDescriptor) FieldDescriptor(org.infinispan.protostream.descriptors.FieldDescriptor) GenericDescriptor(org.infinispan.protostream.descriptors.GenericDescriptor) Json(org.infinispan.commons.dataconversion.internal.Json) FieldDescriptor(org.infinispan.protostream.descriptors.FieldDescriptor)

Example 2 with Type

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

the class AbstractMarshallerCodeGenerator method generateReadMethodBody.

/**
 * Signature of generated method is:
 * <code>
 * public java.lang.Object read(org.infinispan.protostream.ProtoStreamMarshaller.ReadContext $1,
 * java.lang.Object $2) throws java.io.IOException
 * </code>
 */
protected String generateReadMethodBody(ProtoMessageTypeMetadata messageTypeMetadata) {
    // todo [anistor] handle unknown fields for adapters also
    String getUnknownFieldSetFieldStatement = null;
    String setUnknownFieldSetFieldStatement = null;
    if (messageTypeMetadata.getUnknownFieldSetField() != null) {
        getUnknownFieldSetFieldStatement = "o." + messageTypeMetadata.getUnknownFieldSetField().getName();
        setUnknownFieldSetFieldStatement = "o." + messageTypeMetadata.getUnknownFieldSetField().getName() + " = u";
    } else if (messageTypeMetadata.getUnknownFieldSetGetter() != null) {
        getUnknownFieldSetFieldStatement = "o." + messageTypeMetadata.getUnknownFieldSetGetter().getName() + "()";
        setUnknownFieldSetFieldStatement = "o." + messageTypeMetadata.getUnknownFieldSetSetter().getName() + "(u)";
    } else if (messageTypeMetadata.getJavaClass().isAssignableTo(Message.class)) {
        getUnknownFieldSetFieldStatement = "o.getUnknownFieldSet()";
        setUnknownFieldSetFieldStatement = "o.setUnknownFieldSet(u)";
    }
    IndentWriter iw = new IndentWriter();
    iw.append("{\n");
    iw.inc();
    iw.append("final ").append(TagReader.class.getName()).append(" $in = $1.getReader();\n");
    if (messageTypeMetadata.isContainer()) {
        iw.append("Object __v$sizeParam = $1.getParam(\"" + WrappedMessage.CONTAINER_SIZE_CONTEXT_PARAM + "\");\n");
        iw.append("int __v$size = ((java.lang.Integer) __v$sizeParam).intValue();\n");
    }
    // if there is no factory then the class must have setters or the fields should be directly accessible and not be final
    final boolean noFactory = messageTypeMetadata.getFactory() == null;
    if (noFactory) {
        iw.append("final ").append(messageTypeMetadata.getJavaClassName()).append(" o = new ").append(messageTypeMetadata.getJavaClassName()).append("();\n");
    }
    // number of fields that are required and do not have a default value
    int mandatoryFields = 0;
    // fields that should be tracked for presence and be either initialized with defaults if missing at the end
    // or an exception thrown if no default exists
    Map<String, Integer> trackedFields = new LinkedHashMap<>();
    // First pass over fields. Count how many are mandatory and how many need to be tracked for presence.
    for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
        if (fieldMetadata.isRequired() && fieldMetadata.getDefaultValue() == null) {
            mandatoryFields++;
        }
        if (fieldMetadata.isRequired() || fieldMetadata.getDefaultValue() != null && (noFactory || fieldMetadata.isRepeated() || fieldMetadata.getProtobufType() == Type.BYTES)) {
            int trackedFieldsSize = trackedFields.size();
            if (trackedFieldsSize % 64 == 0) {
                // declare a long variable to emulate a bitset in multiple long variables
                iw.append("long __bits$").append(String.valueOf(trackedFieldsSize >> 6)).append(" = 0;\n");
            }
            trackedFields.put(fieldMetadata.getName(), trackedFieldsSize);
        }
    }
    for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
        if (fieldMetadata.isRepeated()) {
            // a collection local variable
            iw.append(fieldMetadata.getCollectionImplementation().getCanonicalName()).append(' ').append(makeCollectionLocalVar(fieldMetadata)).append(" = ");
            if (noDefaults || fieldMetadata.isArray()) {
                iw.append("null");
            } else {
                iw.append("new ").append(fieldMetadata.getCollectionImplementation().getCanonicalName()).append("()");
            }
            iw.append(";\n");
            if (!noFactory && fieldMetadata.isArray()) {
                // an array local variable
                iw.append(fieldMetadata.getJavaTypeName()).append("[] ").append(makeArrayLocalVar(fieldMetadata)).append(" = ");
                if (noDefaults) {
                    iw.append("null");
                } else {
                    iw.append("new ").append(fieldMetadata.getJavaTypeName()).append("[0]");
                }
                iw.append(";\n");
            }
        } else if (!noFactory) {
            // immutable messages need a per-field local variable initialized to default value if any
            iw.append(fieldMetadata.getJavaTypeName()).append(' ').append(makeFieldLocalVar(fieldMetadata));
            Object defaultValue = fieldMetadata.getDefaultValue();
            if (defaultValue != null && fieldMetadata.getProtobufType() != Type.BYTES) {
                // fields of type bytes get assigned default values only at the end to avoid a possibly useless byte[] allocation
                String val = toJavaLiteral(defaultValue, fieldMetadata.getJavaType());
                iw.append(" = ").append(box(val, fieldMetadata.getJavaType()));
            } else {
                if (fieldMetadata.isBoxedPrimitive() || fieldMetadata.getProtobufType() == Type.BYTES || fieldMetadata.getProtobufType().getJavaType() == JavaType.STRING || fieldMetadata.getProtobufType().getJavaType() == JavaType.BYTE_STRING || fieldMetadata.getProtobufType().getJavaType() == JavaType.ENUM || fieldMetadata.getProtobufType().getJavaType() == JavaType.MESSAGE || fieldMetadata.getJavaType().getCanonicalName().equals(Date.class.getCanonicalName()) || fieldMetadata.getJavaType().getCanonicalName().equals(Instant.class.getCanonicalName())) {
                    iw.append(" = null");
                } else if (fieldMetadata.isPrimitive()) {
                    if (fieldMetadata.getProtobufType() == Type.BOOL) {
                        iw.append(" = false");
                    } else {
                        iw.append(" = 0");
                    }
                }
            }
            iw.append(";\n");
        }
    }
    iw.append("boolean done = false;\n");
    iw.append("while (!done) {\n");
    iw.inc();
    iw.append("final int tag = $in.readTag();\n");
    iw.append("switch (tag) {\n");
    iw.inc();
    iw.append("case 0: {\n");
    iw.inc();
    iw.append("done = true;\nbreak;\n");
    iw.dec();
    iw.append("}\n");
    for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
        final String v = makeFieldLocalVar(fieldMetadata);
        iw.append("case ").append(makeFieldTag(fieldMetadata.getNumber(), fieldMetadata.getProtobufType().getWireType())).append(": {\n");
        iw.inc();
        if (BaseProtoSchemaGenerator.generateMarshallerDebugComments) {
            iw.append("// type = ").append(fieldMetadata.getProtobufType().toString()).append(", name = ").append(fieldMetadata.getName()).append('\n');
        }
        switch(fieldMetadata.getProtobufType()) {
            case DOUBLE:
            case FLOAT:
            case INT64:
            case UINT64:
            case INT32:
            case FIXED64:
            case FIXED32:
            case BOOL:
            case STRING:
            case BYTES:
            case UINT32:
            case SFIXED32:
            case SFIXED64:
            case SINT32:
            case SINT64:
                {
                    if (noFactory || fieldMetadata.isRepeated()) {
                        iw.append(fieldMetadata.getJavaTypeName()).append(' ');
                    }
                    iw.append(v).append(" = ").append(box(convert("$in." + makeStreamIOMethodName(fieldMetadata, false) + "()", fieldMetadata), fieldMetadata.getJavaType())).append(";\n");
                    genSetField(iw, fieldMetadata, trackedFields, messageTypeMetadata);
                    break;
                }
            case GROUP:
                {
                    String mdField = initMarshallerDelegateField(iw, fieldMetadata);
                    if (noFactory || fieldMetadata.isRepeated()) {
                        iw.append(fieldMetadata.getJavaTypeName()).append(' ');
                    }
                    iw.append(v).append(" = (").append(fieldMetadata.getJavaTypeName()).append(") readMessage(").append(mdField).append(", $1);\n");
                    iw.append("$in.checkLastTagWas(").append(makeFieldTag(fieldMetadata.getNumber(), WireType.END_GROUP)).append(");\n");
                    genSetField(iw, fieldMetadata, trackedFields, messageTypeMetadata);
                    break;
                }
            case MESSAGE:
                {
                    String mdField = initMarshallerDelegateField(iw, fieldMetadata);
                    iw.append("int length = $in.readUInt32();\n");
                    iw.append("int oldLimit = $in.pushLimit(length);\n");
                    if (noFactory || fieldMetadata.isRepeated()) {
                        iw.append(fieldMetadata.getJavaTypeName()).append(' ');
                    }
                    iw.append(v).append(" = (").append(fieldMetadata.getJavaTypeName()).append(") readMessage(").append(mdField).append(", $1);\n");
                    iw.append("$in.checkLastTagWas(0);\n");
                    iw.append("$in.popLimit(oldLimit);\n");
                    genSetField(iw, fieldMetadata, trackedFields, messageTypeMetadata);
                    break;
                }
            case ENUM:
                {
                    String mdField = initMarshallerDelegateField(iw, fieldMetadata);
                    iw.append("int enumVal = $in.readEnum();\n");
                    if (noFactory || fieldMetadata.isRepeated()) {
                        iw.append(fieldMetadata.getJavaTypeName()).append(' ');
                    }
                    iw.append(v).append(" = (").append(fieldMetadata.getJavaTypeName()).append(") ").append(mdField).append(".getMarshaller().decode(enumVal);\n");
                    iw.append("if (").append(v).append(" == null) {\n");
                    if (getUnknownFieldSetFieldStatement != null) {
                        iw.inc();
                        iw.append(PROTOSTREAM_PACKAGE).append(".UnknownFieldSet u = ").append(getUnknownFieldSetFieldStatement).append(";\n");
                        iw.append("if (u == null) { u = new ").append(PROTOSTREAM_PACKAGE).append(".impl.UnknownFieldSetImpl(); ").append(setUnknownFieldSetFieldStatement).append("; }\n");
                        iw.append("u.putVarintField(").append(String.valueOf(fieldMetadata.getNumber())).append(", enumVal);\n");
                        iw.dec();
                    }
                    iw.append("} else {\n").inc();
                    genSetField(iw, fieldMetadata, trackedFields, messageTypeMetadata);
                    iw.dec().append("}\n");
                    break;
                }
            default:
                throw new IllegalStateException("Unknown field type : " + fieldMetadata.getProtobufType());
        }
        iw.append("break;\n");
        iw.dec();
        iw.append("}\n");
    }
    iw.append("default: {\n");
    iw.inc();
    if (getUnknownFieldSetFieldStatement != null) {
        iw.append(PROTOSTREAM_PACKAGE).append(".UnknownFieldSet u = ").append(getUnknownFieldSetFieldStatement).append(";\n");
        iw.append("if (u == null) u = new ").append(PROTOSTREAM_PACKAGE).append(".impl.UnknownFieldSetImpl();\n");
        iw.append("if (!u.readSingleField(tag, $in)) done = true;\n");
        iw.append("if (!u.isEmpty()) ").append(setUnknownFieldSetFieldStatement).append(";\n");
    } else {
        iw.append("if (!$in.skipField(tag)) done = true;\n");
    }
    iw.dec().append("}\n");
    iw.dec().append("}\n");
    iw.dec().append("}\n");
    // assign defaults to missing fields
    if (BaseProtoSchemaGenerator.generateMarshallerDebugComments) {
        iw.append("\n// default values\n\n");
    }
    for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
        Object defaultValue = fieldMetadata.getDefaultValue();
        if (defaultValue != null && (noFactory || fieldMetadata.isRepeated() || fieldMetadata.getProtobufType() == Type.BYTES)) {
            iw.append("if ").append(makeTestFieldWasNotSet(fieldMetadata, trackedFields)).append(" {\n");
            iw.inc();
            String val = toJavaLiteral(defaultValue, fieldMetadata.getJavaType());
            if (fieldMetadata.isRepeated()) {
                String c = makeCollectionLocalVar(fieldMetadata);
                if (noDefaults || fieldMetadata.isArray()) {
                    iw.append("if (").append(c).append(" == null) ").append(c).append(" = new ").append(fieldMetadata.getCollectionImplementation().getCanonicalName()).append("();\n");
                }
                iw.append(c).append(".add(").append(box(val, typeFactory.fromClass(defaultValue.getClass()))).append(");\n");
            } else {
                if (noFactory) {
                    iw.append(createSetPropExpr(messageTypeMetadata, fieldMetadata, "o", box(val, fieldMetadata.getJavaType()))).append(";\n");
                } else {
                    iw.append(makeFieldLocalVar(fieldMetadata)).append(" = ").append(box(val, fieldMetadata.getJavaType())).append(";\n");
                }
            }
            iw.dec();
            iw.append("}\n");
        }
    }
    for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
        if (fieldMetadata.isRepeated()) {
            String c = makeCollectionLocalVar(fieldMetadata);
            if (fieldMetadata.isArray()) {
                if (fieldMetadata.getDefaultValue() == null) {
                    iw.append("if (").append(c).append(" != null) ");
                }
                iw.append("{\n").inc();
                String a = makeArrayLocalVar(fieldMetadata);
                if (fieldMetadata.getJavaType().isPrimitive()) {
                    if (noFactory) {
                        iw.append(fieldMetadata.getJavaTypeName()).append("[] ");
                    }
                    iw.append(a).append(" = new ").append(fieldMetadata.getJavaTypeName()).append("[").append(c).append(".size()];\n");
                    XClass boxedType = box(fieldMetadata.getJavaType());
                    iw.append("int _j = 0;\nfor (java.util.Iterator _it = ").append(c).append(".iterator(); _it.hasNext();) ").append(a).append("[_j++] = ").append(unbox("((" + boxedType.getName() + ") _it.next())", boxedType)).append(";\n");
                    c = a;
                } else {
                    c = "(" + fieldMetadata.getJavaTypeName() + "[])" + c + ".toArray(new " + fieldMetadata.getJavaTypeName() + "[0])";
                }
            }
            if (noFactory) {
                iw.append(createSetPropExpr(messageTypeMetadata, fieldMetadata, "o", c)).append(";\n");
            } else if (fieldMetadata.isArray() && !fieldMetadata.getJavaType().isPrimitive()) {
                iw.append(makeArrayLocalVar(fieldMetadata)).append(" = ").append(c).append(";\n");
            }
            if (fieldMetadata.isArray()) {
                iw.dec().append('}');
                if (!noDefaults && fieldMetadata.getDefaultValue() == null) {
                    c = "new " + fieldMetadata.getJavaTypeName() + "[0]";
                    iw.append(" else {\n").inc();
                    if (noFactory) {
                        iw.append(createSetPropExpr(messageTypeMetadata, fieldMetadata, "o", c)).append(";\n");
                    } else {
                        iw.append(makeArrayLocalVar(fieldMetadata)).append(" = ").append(c).append(";\n");
                    }
                    iw.dec().append("}\n");
                }
            }
            iw.append('\n');
        }
    }
    // complain about missing required fields
    if (mandatoryFields > 0) {
        List<ProtoFieldMetadata> mandatory = messageTypeMetadata.getFields().values().stream().filter(f -> f.isRequired() && f.getDefaultValue() == null).collect(Collectors.toList());
        iw.append("if (").append(makeTestFieldWasNotSet(mandatory, trackedFields)).append(") {\n");
        iw.inc();
        iw.append("final StringBuilder missing = new StringBuilder();\n");
        boolean first = true;
        for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
            if (fieldMetadata.isRequired()) {
                iw.append("if ").append(makeTestFieldWasNotSet(fieldMetadata, trackedFields)).append(" {\n");
                iw.inc();
                if (first) {
                    first = false;
                } else {
                    iw.append("if (missing.length() > 0) missing.append(\", \");\n");
                }
                iw.append("missing.append(\"").append(fieldMetadata.getName()).append("\");\n");
                iw.dec();
                iw.append("}\n");
            }
        }
        iw.append("throw new java.io.IOException(\"Required field(s) missing from input stream : \" + missing);\n");
        iw.dec();
        iw.append("}\n");
    }
    if (noFactory) {
        // return the instance
        iw.append("return o;\n");
    } else {
        // create and return the instance
        iw.append("return ");
        XExecutable factory = messageTypeMetadata.getFactory();
        if (factory instanceof XConstructor) {
            iw.append("new ").append(messageTypeMetadata.getJavaClassName());
        } else {
            if (factory.isStatic()) {
                iw.append(messageTypeMetadata.getAnnotatedClassName()).append('.').append(factory.getName());
            } else {
                iw.append(ADAPTER_FIELD_NAME).append('.').append(factory.getName());
            }
        }
        iw.append('(');
        boolean first = true;
        for (String paramName : factory.getParameterNames()) {
            if (first) {
                first = false;
                if (messageTypeMetadata.isContainer()) {
                    iw.append("__v$size");
                    continue;
                }
            } else {
                iw.append(", ");
            }
            boolean found = false;
            for (ProtoFieldMetadata fieldMetadata : messageTypeMetadata.getFields().values()) {
                if (fieldMetadata.getPropertyName().equals(paramName)) {
                    String var = fieldMetadata.isRepeated() ? (fieldMetadata.isArray() ? makeArrayLocalVar(fieldMetadata) : makeCollectionLocalVar(fieldMetadata)) : makeFieldLocalVar(fieldMetadata);
                    iw.append(var);
                    found = true;
                    break;
                }
            }
            if (!found) {
                throw new ProtoSchemaBuilderException("Parameter '" + paramName + "' of factory " + factory + " does not map to any Protobuf field");
            }
        }
        iw.append(");\n");
    }
    iw.dec().append("}\n");
    return iw.toString();
}
Also used : Type(org.infinispan.protostream.descriptors.Type) WireType(org.infinispan.protostream.descriptors.WireType) Date(java.util.Date) Collection(java.util.Collection) HashMap(java.util.HashMap) ProtoSchemaBuilderException(org.infinispan.protostream.annotations.ProtoSchemaBuilderException) Message(org.infinispan.protostream.Message) Instant(java.time.Instant) TagWriter(org.infinispan.protostream.TagWriter) XConstructor(org.infinispan.protostream.annotations.impl.types.XConstructor) Collectors(java.util.stream.Collectors) WrappedMessage(org.infinispan.protostream.WrappedMessage) LinkedHashMap(java.util.LinkedHashMap) List(java.util.List) XTypeFactory(org.infinispan.protostream.annotations.impl.types.XTypeFactory) Map(java.util.Map) Optional(java.util.Optional) TagReader(org.infinispan.protostream.TagReader) XClass(org.infinispan.protostream.annotations.impl.types.XClass) SerializationContext(org.infinispan.protostream.SerializationContext) XExecutable(org.infinispan.protostream.annotations.impl.types.XExecutable) JavaType(org.infinispan.protostream.descriptors.JavaType) Instant(java.time.Instant) XClass(org.infinispan.protostream.annotations.impl.types.XClass) LinkedHashMap(java.util.LinkedHashMap) XConstructor(org.infinispan.protostream.annotations.impl.types.XConstructor) XExecutable(org.infinispan.protostream.annotations.impl.types.XExecutable) ProtoSchemaBuilderException(org.infinispan.protostream.annotations.ProtoSchemaBuilderException)

Example 3 with Type

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

the class ProtoStreamReaderImpl method readPrimitiveCollection.

private void readPrimitiveCollection(FieldDescriptor fd, Collection<? super Object> collection, Class<?> elementClass) throws IOException {
    final int expectedTag = fd.getWireTag();
    Type type = fd.getType();
    while (true) {
        Object o = messageContext.unknownFieldSet.consumeTag(expectedTag);
        if (o == null) {
            break;
        }
        // todo check that (o.getClass() == elementClass)
        collection.add(convertWireTypeToJavaType(type, o));
    }
    while (true) {
        int tag = messageContext.in.readTag();
        if (tag == 0) {
            break;
        }
        if (tag == expectedTag) {
            Object value;
            switch(type) {
                case DOUBLE:
                    value = messageContext.in.readDouble();
                    break;
                case FLOAT:
                    value = messageContext.in.readFloat();
                    break;
                case BOOL:
                    value = messageContext.in.readBool();
                    break;
                case STRING:
                    value = messageContext.in.readString();
                    break;
                case BYTES:
                    value = messageContext.in.readByteArray();
                    break;
                case INT64:
                    value = messageContext.in.readInt64();
                    break;
                case UINT64:
                    value = messageContext.in.readUInt64();
                    break;
                case FIXED64:
                    value = messageContext.in.readFixed64();
                    break;
                case SFIXED64:
                    value = messageContext.in.readSFixed64();
                    break;
                case SINT64:
                    value = messageContext.in.readSInt64();
                    break;
                case INT32:
                    value = messageContext.in.readInt32();
                    break;
                case FIXED32:
                    value = messageContext.in.readFixed32();
                    break;
                case UINT32:
                    value = messageContext.in.readUInt32();
                    break;
                case SFIXED32:
                    value = messageContext.in.readSFixed32();
                    break;
                case SINT32:
                    value = messageContext.in.readSInt32();
                    break;
                default:
                    throw new IllegalStateException("Unexpected field type : " + type);
            }
            collection.add(value);
        } else {
            messageContext.unknownFieldSet.readSingleField(tag, messageContext.in);
        }
    }
}
Also used : Type(org.infinispan.protostream.descriptors.Type) WireType(org.infinispan.protostream.descriptors.WireType) JavaType(org.infinispan.protostream.descriptors.JavaType)

Example 4 with Type

use of org.infinispan.protostream.descriptors.Type 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 5 with Type

use of org.infinispan.protostream.descriptors.Type 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

Type (org.infinispan.protostream.descriptors.Type)7 JavaType (org.infinispan.protostream.descriptors.JavaType)6 HashMap (java.util.HashMap)4 List (java.util.List)4 Map (java.util.Map)4 FieldDescriptor (org.infinispan.protostream.descriptors.FieldDescriptor)3 WireType (org.infinispan.protostream.descriptors.WireType)3 File (java.io.File)2 URL (java.net.URL)2 ArrayList (java.util.ArrayList)2 Optional (java.util.Optional)2 Collectors (java.util.stream.Collectors)2 Assertions.assertThat (org.fest.assertions.api.Assertions.assertThat)2 AnnotationParserException (org.infinispan.protostream.AnnotationParserException)2 DescriptorParserException (org.infinispan.protostream.DescriptorParserException)2 FileDescriptorSource (org.infinispan.protostream.FileDescriptorSource)2 Configuration (org.infinispan.protostream.config.Configuration)2 AnnotationElement (org.infinispan.protostream.descriptors.AnnotationElement)2 Descriptor (org.infinispan.protostream.descriptors.Descriptor)2 EnumDescriptor (org.infinispan.protostream.descriptors.EnumDescriptor)2