/** Returns a GraphQLOutputType generated from a FieldDescriptor. */ static GraphQLOutputType convertType(FieldDescriptor fieldDescriptor) { final GraphQLOutputType type; if (fieldDescriptor.getType() == Type.MESSAGE) { type = getReference(fieldDescriptor.getMessageType()); } else if (fieldDescriptor.getType() == Type.GROUP) { type = getReference(fieldDescriptor.getMessageType()); } else if (fieldDescriptor.getType() == Type.ENUM) { type = getReference(fieldDescriptor.getEnumType()); } else { type = TYPE_MAP.get(fieldDescriptor.getType()); } if (type == null) { throw new RuntimeException("Unknown type: " + fieldDescriptor.getType()); } if (fieldDescriptor.isRepeated()) { return new GraphQLList(type); } else { return type; } }
/** * Returns the {@link Method} that sets a single value of the field. For repeated and map fields, * this is the add or put method that only take an individual element; */ Method setValueMethod() { StringBuilder setter = new StringBuilder(); final Class<?>[] args; if (field.isMapField()) { setter.append("put"); args = new Class<?>[] {mapKeyField.javaClass(), javaClass()}; } else { args = new Class<?>[] {javaClass()}; if (field.isRepeated()) { setter.append("add"); } else { setter.append("set"); } } setter.append(camelCaseName); if (valueType() == Type.ENUM) { setter.append("Value"); } try { return builderClass.getDeclaredMethod(setter.toString(), args); } catch (NoSuchMethodException e) { throw new IllegalStateException("Could not find setter.", e); } }
/** * Populates a JSON schema for a repeated primitive proto field. * * @param field the field being considered * @param property the JSON schema being built */ private void populateRepeatedPrimitiveSchema(FieldDescriptor field, JsonSchema.Builder property) { property.setType(JsonType.ARRAY); JsonSchema.Builder itemsSchema = JsonSchema.newBuilder(); if (treatLongsAsStrings && field.getJavaType().equals(JavaType.LONG) && !transforms.containsKey(field.getName())) { itemsSchema.setType(JsonType.STRING); if (field.getType().equals(Type.UINT64) || field.getType().equals(Type.FIXED64)) { itemsSchema.setFormat(UINT64_STRING_FORMAT); } else { itemsSchema.setFormat(INT64_STRING_FORMAT); } } else { itemsSchema.setType(getReifiedFieldType(field)); } property.setItems(itemsSchema); if (field.getType().equals(Type.ENUM)) { for (EnumValueDescriptor enumValue : field.getEnumType().getValues()) { property.addEnum(PROTO_ENUM_CASE_FORMAT.to( enumCaseFormat, enumValue.getName())); } } }
/** * Generates a non-default value for the given message field. * * <p>All the protobuf types are supported including nested {@link Message}s and * the {@code enum}s. * * @param field {@link FieldDescriptor} to take the type info from * @return a non-default generated value of type of the given field */ @SuppressWarnings("OverlyComplexMethod") private static Object valueFor(FieldDescriptor field) { final Type type = field.getType(); final JavaType javaType = type.getJavaType(); final Random random = new SecureRandom(); switch (javaType) { case INT: return random.nextInt(); case LONG: return random.nextLong(); case FLOAT: return random.nextFloat(); case DOUBLE: return random.nextDouble(); case BOOLEAN: return random.nextBoolean(); case STRING: final byte[] bytes = new byte[8]; random.nextBytes(bytes); return new String(bytes); case BYTE_STRING: final byte[] bytesPrimitive = new byte[8]; random.nextBytes(bytesPrimitive); return ByteString.copyFrom(bytesPrimitive); case ENUM: return enumValueFor(field, random); case MESSAGE: return messageValueFor(field); default: throw new IllegalArgumentException(format("Field type %s is not supported.", type)); } }
/** * This is a helper for decodeMessageValue. Decode a single field and return * the value. Assume the field type is not Type.MESSAGE. */ private static Object decodeFieldValue (FieldDescriptor field, int tlvType, TlvDecoder decoder, int endOffset) throws EncodingException { if (field.getType() == Type.UINT32) return (int)decoder.readNonNegativeIntegerTlv(tlvType); else if (field.getType() == Type.UINT64) return decoder.readNonNegativeIntegerTlv(tlvType); else if (field.getType() == Type.ENUM) return field.getEnumType().findValueByNumber ((int)decoder.readNonNegativeIntegerTlv(tlvType)); else if (field.getType() == Type.BYTES) return ByteString.copyFrom(decoder.readBlobTlv(tlvType)); else if (field.getType() == Type.STRING) { try { ByteBuffer byteBuffer = decoder.readBlobTlv(tlvType); // Use Blob to get the byte array. return new String(new Blob(byteBuffer, false).getImmutableArray(), "UTF-8"); } catch (UnsupportedEncodingException ex) { // We don't expect this to happen. throw new Error("UTF-8 decoder not supported: " + ex.getMessage()); } } else if (field.getType() == Type.BOOL) return decoder.readBooleanTlv(tlvType, endOffset); else throw new Error("ProtobufTlv.decode: Unknown field type"); }
/** * Returns a new schema in which the given field will be delegated to the * specified schema. * * <p>The field must be a submessage and its type must match that of * {@code schema}. * * @param fieldName the name of the field, which must be of object type * @param schemaName the name of the schema to delegate this field to */ public NamedSchema useSchema(String fieldName, String schemaName) { Preconditions.checkNotNull(fieldName); Preconditions.checkNotNull(schemaName); Preconditions.checkState(has(fieldName)); FieldDescriptor field = fields.get(fieldName); Preconditions.checkArgument(Type.MESSAGE.equals(field.getType())); ImmutableMap.Builder<String, String> subObjectSchemasCopy = ImmutableMap.builder(); subObjectSchemasCopy.putAll(subObjectSchemas); subObjectSchemasCopy.put(fieldName, schemaName); return new NamedSchema(descriptor, name, skippedFields, constants, enumCaseFormat, substitutions, transforms, mappings, descriptions, subObjectSchemasCopy.build(), formats, treatLongsAsStrings); }
private static void populate(Descriptor descriptor, Multimap<Descriptor, Descriptor> graphBuilder) { if (graphBuilder.containsKey(descriptor)) { return; } for (FieldDescriptor field : descriptor.getFields()) { if (Type.MESSAGE.equals(field.getType())) { Descriptors.Descriptor subDescriptor = field.getMessageType(); graphBuilder.put(descriptor, subDescriptor); populate(subDescriptor, graphBuilder); } } }
public AttributeValue buildAttributeValue(Object value) { Type type = field.getType(); if (type == Type.BYTES) { ByteString b = (ByteString) value; AttributeValue attributeValue = new AttributeValue().withB(b.asReadOnlyByteBuffer()); return attributeValue; // AttributeValue attributeValue = tableInfo.mapToAttributeValue(fieldDescriptor, fieldValue); // expected.put(attributeName, new ExpectedAttributeValue(toAttributeValue(where.getVersion()))); } else { throw new UnsupportedOperationException("Unsupport field type: " + type); } }
private static void encodeMessageValue(Message message, TlvEncoder encoder) { // Note: We can't use ListFields because it sorts by field number. Descriptor descriptor = message.getDescriptorForType(); // Go in reverse so that we encode backwards. List fields = descriptor.getFields(); for (int i = fields.size() - 1; i >= 0; --i) { FieldDescriptor field = (FieldDescriptor)fields.get(i); int tlvType = field.getNumber(); int valueCount = 0; if (field.isRepeated()) valueCount = message.getRepeatedFieldCount(field); else { if (message.hasField(field)) valueCount = 1; } // Reverse so that we encode backwards. for (int iValue = valueCount - 1; iValue >= 0; --iValue) { Object value; if (field.isRepeated()) value = message.getRepeatedField(field, iValue); else value = message.getField(field); if (field.getType() == Type.MESSAGE) { int saveLength = encoder.getLength(); // Encode backwards. encodeMessageValue((Message)value, encoder); encoder.writeTypeAndLength(tlvType, encoder.getLength() - saveLength); } else if (field.getType() == Type.UINT32) encoder.writeNonNegativeIntegerTlv(tlvType, (Integer)value); else if (field.getType() == Type.UINT64) encoder.writeNonNegativeIntegerTlv(tlvType, (Long)value); else if (field.getType() == Type.ENUM) { int intValue = ((EnumValueDescriptor)value).getNumber(); if (intValue < 0) throw new Error("ProtobufTlv.encode: ENUM value may not be negative"); encoder.writeNonNegativeIntegerTlv(tlvType, intValue); } else if (field.getType() == Type.BYTES) encoder.writeBlobTlv(tlvType, ((ByteString)value).asReadOnlyByteBuffer()); else if (field.getType() == Type.STRING) // Use Blob to UTF-8 encode and get a ByteBuffer. encoder.writeBlobTlv(tlvType, new Blob((String)value).buf()); else if (field.getType() == Type.BOOL) { if ((boolean)(Boolean)value) encoder.writeTypeAndLength(tlvType, 0); } else throw new Error("ProtobufTlv.encode: Unknown field type"); } } }
/** Returns true if fieldDescriptor holds a sanitized proto type. */ public static boolean isSanitizedContentField(FieldDescriptor fieldDescriptor) { return fieldDescriptor.getType() == Type.MESSAGE && SafeStringTypes.SAFE_PROTO_TO_SANITIZED_TYPE.containsKey( fieldDescriptor.getMessageType().getFullName()); }
private void generateProtoFromDescriptor(FieldDescriptor descriptor, Appendable out, String indent, Map<Descriptor, Boolean> descriptors) throws IOException { out.append(indent); if (descriptor.isRequired()) { out.append("required "); } if (descriptor.isOptional()) { out.append("optional "); } if (descriptor.isRepeated()) { out.append("repeated "); } if (descriptor.getType().equals(Type.MESSAGE)) { out.append(descriptor.getMessageType().getFullName() + " "); Descriptor messageType = descriptor.getMessageType(); if (descriptors.get(messageType) == null) { descriptors.put(messageType, false); } } else if (descriptor.getType().equals(Type.ENUM)) { out.append(descriptor.getEnumType().getFullName() + " "); } else { out.append(descriptor.getType().toString().toLowerCase() + " "); } out.append(descriptor.getName() + " = " + descriptor.getNumber()); if (descriptor.hasDefaultValue()) { out.append(" [default = "); Object defaultValue = descriptor.getDefaultValue(); if (defaultValue instanceof EnumValueDescriptor) { out.append(((EnumValueDescriptor) defaultValue).getName()); } out.append("]"); } out.append(";\n"); }
/** * Returns a new schema that will serialize repeated objects as a JSON * object instead of a JSON array. * * <p>This transformation is useful in cases where the source object * contains a list of objects identified by a given field. Normally, such * a list would be serialized as:<pre>{@code * * "users": [ * {"username": "lrichie", name: "Lionel Richie"}, * {"username": "stwain", "name": "Shania Twain"} * ]}</pre> * * <p>A common JSON idiom is to represent such collections as pseudo-maps, * i.e.objects with non-predefined keys:<pre>{@code * * "users": { * "lrichie": {"name": "Lionel Richie"}, * "stwain": {"name": "Shania Twain"} * }}</pre> * * <p>To achieve this effect, call this method with {@code "users"} and * {@code "username"} as parameters, respectively. * * @param fieldName Must point to a repeated object field in this schema * @param keyFieldName Must be a string field in the repeated field */ public NamedSchema mapRepeatedField(String fieldName, String keyFieldName) { Preconditions.checkNotNull(fieldName); Preconditions.checkArgument(has(fieldName)); Preconditions.checkNotNull(keyFieldName); FieldDescriptor field = fields.get(fieldName); Preconditions.checkArgument(field.isRepeated() && Type.MESSAGE.equals(field.getType())); Descriptor fieldDescriptor = field.getMessageType(); boolean found = false; FieldDescriptor keyField = null; for (FieldDescriptor subField : fieldDescriptor.getFields()) { if (subField.getName().equals(keyFieldName)) { found = true; keyField = subField; } } if (!found || keyField.isRepeated() || !Type.STRING.equals(keyField.getType())) { throw new IllegalArgumentException(); } ImmutableMap.Builder<String, FieldDescriptor> mappingsCopy = ImmutableMap.<String, FieldDescriptor>builder(); mappingsCopy.putAll(mappings); mappingsCopy.put(fieldName, keyField); return new NamedSchema(descriptor, name, skippedFields, constants, enumCaseFormat, substitutions, transforms, mappingsCopy.build(), descriptions, subObjectSchemas, formats, treatLongsAsStrings); }
/** * Returns the {@link Type} of the actual value of this field, which for map fields is the type of * the map's value. */ FieldDescriptor.Type valueType() { return valueField().descriptor().getType(); }