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);
});
}
}
}
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();
}
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);
}
}
}
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;
}
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);
}
}
}
}
Aggregations