Search in sources :

Example 1 with XExecutable

use of org.infinispan.protostream.annotations.impl.types.XExecutable 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)

Aggregations

Instant (java.time.Instant)1 Collection (java.util.Collection)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 Map (java.util.Map)1 Optional (java.util.Optional)1 Collectors (java.util.stream.Collectors)1 Message (org.infinispan.protostream.Message)1 SerializationContext (org.infinispan.protostream.SerializationContext)1 TagReader (org.infinispan.protostream.TagReader)1 TagWriter (org.infinispan.protostream.TagWriter)1 WrappedMessage (org.infinispan.protostream.WrappedMessage)1 ProtoSchemaBuilderException (org.infinispan.protostream.annotations.ProtoSchemaBuilderException)1 XClass (org.infinispan.protostream.annotations.impl.types.XClass)1 XConstructor (org.infinispan.protostream.annotations.impl.types.XConstructor)1 XExecutable (org.infinispan.protostream.annotations.impl.types.XExecutable)1 XTypeFactory (org.infinispan.protostream.annotations.impl.types.XTypeFactory)1 JavaType (org.infinispan.protostream.descriptors.JavaType)1