/** Returns the type to import for {@code type}. */ private @Nullable ProtoType importedType(ProtoType type) { // Map key type is always scalar. if (type.isMap()) type = type.valueType(); return type.isScalar() ? null : type; }
private void mark(ProtoType type) { // Mark the map type as it's non-scalar and transitively reachable. if (type.isMap()) { marks.mark(type); // Map key type is always scalar. No need to mark it. type = type.valueType(); } if (marks.mark(type)) { queue.add(type); // The transitive dependencies of this type must be visited. } }
private MethodSpec messageHashCode(NameAllocator nameAllocator, MessageType type) { NameAllocator localNameAllocator = nameAllocator.clone(); String resultName = localNameAllocator.newName("result"); MethodSpec.Builder result = MethodSpec.methodBuilder("hashCode") .addAnnotation(Override.class) .addModifiers(PUBLIC) .returns(int.class); List<Field> fields = type.fieldsAndOneOfFields(); if (fields.isEmpty()) { result.addStatement("return unknownFields().hashCode()"); return result.build(); } result.addStatement("int $N = super.hashCode", resultName); result.beginControlFlow("if ($N == 0)", resultName); result.addStatement("$N = unknownFields().hashCode()", resultName); for (Field field : fields) { String fieldName = localNameAllocator.get(field); result.addCode("$1N = $1N * 37 + ", resultName); if (field.isRepeated() || field.isRequired() || field.type().isMap()) { result.addStatement("$L.hashCode()", fieldName); } else { result.addStatement("($1L != null ? $1L.hashCode() : 0)", fieldName); } } result.addStatement("super.hashCode = $N", resultName); result.endControlFlow(); result.addStatement("return $N", resultName); return result.build(); }
private MethodSpec newBuilder(NameAllocator nameAllocator, MessageType message) { NameAllocator localNameAllocator = nameAllocator.clone(); String builderName = localNameAllocator.newName("builder"); ClassName javaType = (ClassName) typeName(message.type()); ClassName builderJavaType = javaType.nestedClass("Builder"); MethodSpec.Builder result = MethodSpec.methodBuilder("newBuilder") .addAnnotation(Override.class) .addModifiers(PUBLIC) .returns(builderJavaType) .addStatement("$1T $2L = new $1T()", builderJavaType, builderName); List<Field> fields = message.fieldsAndOneOfFields(); for (Field field : fields) { String fieldName = localNameAllocator.get(field); if (field.isRepeated() || field.type().isMap()) { result.addStatement("$1L.$2L = $3T.copyOf($2S, $2L)", builderName, fieldName, Internal.class); } else { result.addStatement("$1L.$2L = $2L", builderName, fieldName); } } result.addStatement("$L.addUnknownFields(unknownFields())", builderName); result.addStatement("return $L", builderName); return result.build(); }
/** Returns the initial value of {@code field}, or null if it is doesn't have one. */ private @Nullable CodeBlock initialValue(Field field) { if (field.isPacked() || field.isRepeated()) { return CodeBlock.of("$T.newMutableList()", Internal.class); } else if (field.type().isMap()) { return CodeBlock.of("$T.newMutableMap()", Internal.class); } else { return null; } }
private MethodSpec setter( NameAllocator nameAllocator, TypeName builderType, OneOf oneOf, Field field) { TypeName javaType = fieldType(field); String fieldName = nameAllocator.get(field); MethodSpec.Builder result = MethodSpec.methodBuilder(fieldName) .addModifiers(PUBLIC) .addParameter(javaType, fieldName) .returns(builderType); if (!field.documentation().isEmpty()) { result.addJavadoc("$L\n", sanitizeJavadoc(field.documentation())); } if (field.isDeprecated()) { result.addAnnotation(Deprecated.class); } if (field.isRepeated() || field.type().isMap()) { result.addStatement("$T.checkElementsNotNull($L)", Internal.class, fieldName); } result.addStatement("this.$L = $L", fieldName, fieldName); if (oneOf != null) { for (Field other : oneOf.fields()) { if (field != other) { result.addStatement("this.$L = null", nameAllocator.get(other)); } } } result.addStatement("return this"); return result.build(); }
private TypeName fieldType(Field field) { ProtoType type = field.type(); if (type.isMap()) { return ParameterizedTypeName.get(ClassName.get(Map.class), typeName(type.keyType()), typeName(type.valueType())); } TypeName messageType = typeName(type); return field.isRepeated() ? listOf(messageType) : messageType; }
private MethodSpec messageEquals(NameAllocator nameAllocator, MessageType type) { NameAllocator localNameAllocator = nameAllocator.clone(); String otherName = localNameAllocator.newName("other"); String oName = localNameAllocator.newName("o"); TypeName javaType = typeName(type.type()); MethodSpec.Builder result = MethodSpec.methodBuilder("equals") .addAnnotation(Override.class) .addModifiers(PUBLIC) .returns(boolean.class) .addParameter(Object.class, otherName); List<Field> fields = type.fieldsAndOneOfFields(); if (fields.isEmpty()) { result.addStatement("return $N instanceof $T", otherName, javaType); return result.build(); } result.addStatement("if ($N == this) return true", otherName); result.addStatement("if (!($N instanceof $T)) return false", otherName, javaType); result.addStatement("$T $N = ($T) $N", javaType, oName, javaType, otherName); result.addCode("$[return unknownFields().equals($N.unknownFields())", oName); for (Field field : fields) { String fieldName = localNameAllocator.get(field); if (field.isRequired() || field.isRepeated() || field.type().isMap()) { result.addCode("\n&& $1L.equals($2N.$1L)", fieldName, oName); } else { result.addCode("\n&& $1T.equals($2L, $3N.$2L)", Internal.class, fieldName, oName); } } result.addCode(";\n$]"); return result.build(); }
private MethodSpec messageToString(NameAllocator nameAllocator, MessageType type) { NameAllocator localNameAllocator = nameAllocator.clone(); MethodSpec.Builder result = MethodSpec.methodBuilder("toString") .addAnnotation(Override.class) .addModifiers(PUBLIC) .returns(String.class); String builderName = localNameAllocator.newName("builder"); result.addStatement("$1T $2N = new $1T()", StringBuilder.class, builderName); for (Field field : type.fieldsAndOneOfFields()) { String fieldName = nameAllocator.get(field); if (field.isRepeated() || field.type().isMap()) { result.addCode("if (!$N.isEmpty()) ", fieldName); } else if (!field.isRequired()) { result.addCode("if ($N != null) ", fieldName); } if (field.isRedacted()) { result.addStatement("$N.append(\", $N=██\")", builderName, field.name()); } else { result.addStatement("$N.append(\", $N=\").append($L)", builderName, field.name(), fieldName); } } result.addStatement("return builder.replace(0, 2, \"$L{\").append('}').toString()", type.type().simpleName()); return result.build(); }
public ProtoAdapter<Object> get(ProtoType protoType) { if (protoType.isMap()) throw new UnsupportedOperationException("map types not supported"); ProtoAdapter<?> result = adapterMap.get(protoType); if (result != null) { return (ProtoAdapter<Object>) result; } Type type = schema.getType(protoType); if (type == null) { throw new IllegalArgumentException("unknown type: " + protoType); } if (type instanceof EnumType) { EnumAdapter enumAdapter = new EnumAdapter((EnumType) type); adapterMap.put(protoType, enumAdapter); return enumAdapter; } if (type instanceof MessageType) { MessageAdapter messageAdapter = new MessageAdapter(includeUnknown); // Put the adapter in the map early to mitigate the recursive calls to get() made below. adapterMap.put(protoType, messageAdapter); for (com.squareup.wire.schema.Field field : ((MessageType) type).fields()) { Field fieldAdapter = new Field( field.name(), field.tag(), field.isRepeated(), get(field.type())); messageAdapter.fieldsByName.put(field.name(), fieldAdapter); messageAdapter.fieldsByTag.put(field.tag(), fieldAdapter); } return (ProtoAdapter) messageAdapter; } throw new IllegalArgumentException("unexpected type: " + protoType); }
Field retainAll(Schema schema, MarkSet markSet) { // For map types only the value can participate in pruning as the key will always be scalar. if (type.isMap() && !markSet.contains(type.valueType())) return null; if (!markSet.contains(type)) return null; Field result = new Field(packageName, location, label, name, documentation, tag, defaultValue, elementType, options.retainAll(schema, markSet), extension); result.type = type; result.deprecated = deprecated; result.packed = packed; result.redacted = redacted; return result; }
private CodeBlock singleAdapterFor(Field field) { return field.type().isMap() ? CodeBlock.of("$N", field.name()) : singleAdapterFor(field.type()); }
if (field.type().isMap()) { TypeName adapterType = adapterOf(fieldType(field)); adapter.addField(FieldSpec.builder(adapterType, field.name(), PRIVATE, FINAL)
if (field.isRepeated()) { result.addStatement("builder.$N = $T.emptyList()", fieldName, Collections.class); } else if (field.type().isMap()) { result.addStatement("builder.$N = $T.emptyMap()", fieldName, Collections.class); } else { result.addStatement("$T.redactElements(builder.$N, $L)", Internal.class, fieldName, adapter); } else if (field.type().isMap()) {
void validateImport(Location location, ProtoType type) { // Map key type is always scalar. No need to validate it. if (type.isMap()) type = type.valueType(); if (type.isScalar()) return; String path = location.path(); String requiredImport = get(type).location().path(); if (!path.equals(requiredImport) && !imports.containsEntry(path, requiredImport)) { addError("%s needs to import %s", path, requiredImport); } }
private CodeBlock singleAdapterFor(ProtoType type) { CodeBlock.Builder result = CodeBlock.builder(); if (type.isScalar()) { result.add("$T.$L", ADAPTER, type.simpleName().toUpperCase(Locale.US)); } else if (type.isMap()) { throw new IllegalArgumentException("Cannot create single adapter for map type " + type); } else { AdapterConstant adapterConstant = profile.getAdapter(type); if (adapterConstant != null) { result.add("$T.$L", adapterConstant.className, adapterConstant.memberName); } else { result.add("$T.ADAPTER", typeName(type)); } } return result.build(); }
if (field.isRepeated() || field.type().isMap()) { result.addStatement("this.$1L = $2T.immutableCopyOf($1S, $3L)", fieldName, Internal.class, fieldAccessName);
private CodeBlock decodeAndAssign(Field field, NameAllocator nameAllocator, boolean useBuilder) { String fieldName = nameAllocator.get(field); CodeBlock decode = CodeBlock.of("$L.decode(reader)", singleAdapterFor(field)); if (field.isRepeated()) { return useBuilder ? CodeBlock.of("builder.$L.add($L)", fieldName, decode) : CodeBlock.of("$L.add($L)", fieldName, decode); } else if (field.type().isMap()) { return useBuilder ? CodeBlock.of("builder.$L.putAll($L)", fieldName, decode) : CodeBlock.of("$L.putAll($L)", fieldName, decode); } else { return useBuilder ? CodeBlock.of("builder.$L($L)", fieldName, decode) : CodeBlock.of("$L = $L", fieldName, decode); } }
private ProtoType resolveType(String name, boolean messageOnly) { ProtoType type = ProtoType.get(name); if (type.isScalar()) { if (messageOnly) { addError("expected a message but was %s", name); } return type; } if (type.isMap()) { if (messageOnly) { addError("expected a message but was %s", name); } ProtoType keyType = resolveType(type.keyType().toString(), false); ProtoType valueType = resolveType(type.valueType().toString(), false); return new ProtoType(keyType, valueType, name); } Type resolved = resolve(name, protoTypeNames); if (resolved == null) { addError("unable to resolve %s", name); return ProtoType.BYTES; // Just return any placeholder. } if (messageOnly && !(resolved instanceof MessageType)) { addError("expected a message but was %s", name); return ProtoType.BYTES; // Just return any placeholder. } return resolved.type(); }
private AnnotationSpec wireFieldAnnotation(Field field) { AnnotationSpec.Builder result = AnnotationSpec.builder(WireField.class); int tag = field.tag(); result.addMember("tag", String.valueOf(tag)); if (field.type().isMap()) { result.addMember("keyAdapter", "$S", adapterString(field.type().keyType())); result.addMember("adapter", "$S", adapterString(field.type().valueType())); } else { result.addMember("adapter", "$S", adapterString(field.type())); } if (!field.isOptional()) { if (field.isPacked()) { result.addMember("label", "$T.PACKED", WireField.Label.class); } else if (field.label() != null) { result.addMember("label", "$T.$L", WireField.Label.class, field.label()); } } if (field.isRedacted()) { result.addMember("redacted", "true"); } return result.build(); }