// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.google.protobuf;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;

Enumeration identifying all relevant type information for a protobuf field.
/** Enumeration identifying all relevant type information for a protobuf field. */
@ExperimentalApi public enum FieldType { DOUBLE(0, Collection.SCALAR, JavaType.DOUBLE), FLOAT(1, Collection.SCALAR, JavaType.FLOAT), INT64(2, Collection.SCALAR, JavaType.LONG), UINT64(3, Collection.SCALAR, JavaType.LONG), INT32(4, Collection.SCALAR, JavaType.INT), FIXED64(5, Collection.SCALAR, JavaType.LONG), FIXED32(6, Collection.SCALAR, JavaType.INT), BOOL(7, Collection.SCALAR, JavaType.BOOLEAN), STRING(8, Collection.SCALAR, JavaType.STRING), MESSAGE(9, Collection.SCALAR, JavaType.MESSAGE), BYTES(10, Collection.SCALAR, JavaType.BYTE_STRING), UINT32(11, Collection.SCALAR, JavaType.INT), ENUM(12, Collection.SCALAR, JavaType.ENUM), SFIXED32(13, Collection.SCALAR, JavaType.INT), SFIXED64(14, Collection.SCALAR, JavaType.LONG), SINT32(15, Collection.SCALAR, JavaType.INT), SINT64(16, Collection.SCALAR, JavaType.LONG), GROUP(17, Collection.SCALAR, JavaType.MESSAGE), DOUBLE_LIST(18, Collection.VECTOR, JavaType.DOUBLE), FLOAT_LIST(19, Collection.VECTOR, JavaType.FLOAT), INT64_LIST(20, Collection.VECTOR, JavaType.LONG), UINT64_LIST(21, Collection.VECTOR, JavaType.LONG), INT32_LIST(22, Collection.VECTOR, JavaType.INT), FIXED64_LIST(23, Collection.VECTOR, JavaType.LONG), FIXED32_LIST(24, Collection.VECTOR, JavaType.INT), BOOL_LIST(25, Collection.VECTOR, JavaType.BOOLEAN), STRING_LIST(26, Collection.VECTOR, JavaType.STRING), MESSAGE_LIST(27, Collection.VECTOR, JavaType.MESSAGE), BYTES_LIST(28, Collection.VECTOR, JavaType.BYTE_STRING), UINT32_LIST(29, Collection.VECTOR, JavaType.INT), ENUM_LIST(30, Collection.VECTOR, JavaType.ENUM), SFIXED32_LIST(31, Collection.VECTOR, JavaType.INT), SFIXED64_LIST(32, Collection.VECTOR, JavaType.LONG), SINT32_LIST(33, Collection.VECTOR, JavaType.INT), SINT64_LIST(34, Collection.VECTOR, JavaType.LONG), DOUBLE_LIST_PACKED(35, Collection.PACKED_VECTOR, JavaType.DOUBLE), FLOAT_LIST_PACKED(36, Collection.PACKED_VECTOR, JavaType.FLOAT), INT64_LIST_PACKED(37, Collection.PACKED_VECTOR, JavaType.LONG), UINT64_LIST_PACKED(38, Collection.PACKED_VECTOR, JavaType.LONG), INT32_LIST_PACKED(39, Collection.PACKED_VECTOR, JavaType.INT), FIXED64_LIST_PACKED(40, Collection.PACKED_VECTOR, JavaType.LONG), FIXED32_LIST_PACKED(41, Collection.PACKED_VECTOR, JavaType.INT), BOOL_LIST_PACKED(42, Collection.PACKED_VECTOR, JavaType.BOOLEAN), UINT32_LIST_PACKED(43, Collection.PACKED_VECTOR, JavaType.INT), ENUM_LIST_PACKED(44, Collection.PACKED_VECTOR, JavaType.ENUM), SFIXED32_LIST_PACKED(45, Collection.PACKED_VECTOR, JavaType.INT), SFIXED64_LIST_PACKED(46, Collection.PACKED_VECTOR, JavaType.LONG), SINT32_LIST_PACKED(47, Collection.PACKED_VECTOR, JavaType.INT), SINT64_LIST_PACKED(48, Collection.PACKED_VECTOR, JavaType.LONG), GROUP_LIST(49, Collection.VECTOR, JavaType.MESSAGE), MAP(50, Collection.MAP, JavaType.VOID); private final JavaType javaType; private final int id; private final Collection collection; private final Class<?> elementType; private final boolean primitiveScalar; FieldType(int id, Collection collection, JavaType javaType) { this.id = id; this.collection = collection; this.javaType = javaType; switch (collection) { case MAP: elementType = javaType.getBoxedType(); break; case VECTOR: elementType = javaType.getBoxedType(); break; case SCALAR: default: elementType = null; break; } boolean primitiveScalar = false; if (collection == Collection.SCALAR) { switch (javaType) { case BYTE_STRING: case MESSAGE: case STRING: break; default: primitiveScalar = true; break; } } this.primitiveScalar = primitiveScalar; }
A reliable unique identifier for this type.
/** A reliable unique identifier for this type. */
public int id() { return id; }
Gets the JavaType for this field. For lists, this identifies the type of the elements contained within the list.
/** * Gets the {@link JavaType} for this field. For lists, this identifies the type of the elements * contained within the list. */
public JavaType getJavaType() { return javaType; }
Indicates whether a list field should be represented on the wire in packed form.
/** Indicates whether a list field should be represented on the wire in packed form. */
public boolean isPacked() { return Collection.PACKED_VECTOR.equals(collection); }
Indicates whether this field type represents a primitive scalar value. If this is true, then isScalar() will also be true.
/** * Indicates whether this field type represents a primitive scalar value. If this is {@code true}, * then {@link #isScalar()} will also be {@code true}. */
public boolean isPrimitiveScalar() { return primitiveScalar; }
Indicates whether this field type represents a scalar value.
/** Indicates whether this field type represents a scalar value. */
public boolean isScalar() { return collection == Collection.SCALAR; }
Indicates whether this field represents a list of values.
/** Indicates whether this field represents a list of values. */
public boolean isList() { return collection.isList(); }
Indicates whether this field represents a map.
/** Indicates whether this field represents a map. */
public boolean isMap() { return collection == Collection.MAP; }
Indicates whether or not this FieldType can be applied to the given Field.
/** Indicates whether or not this {@link FieldType} can be applied to the given {@link Field}. */
public boolean isValidForField(Field field) { if (Collection.VECTOR.equals(collection)) { return isValidForList(field); } else { return javaType.getType().isAssignableFrom(field.getType()); } } private boolean isValidForList(Field field) { Class<?> clazz = field.getType(); if (!javaType.getType().isAssignableFrom(clazz)) { // The field isn't a List type. return false; } Type[] types = EMPTY_TYPES; Type genericType = field.getGenericType(); if (genericType instanceof ParameterizedType) { types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments(); } Type listParameter = getListParameter(clazz, types); if (!(listParameter instanceof Class)) { // It's a wildcard, we should allow anything in the list. return true; } return elementType.isAssignableFrom((Class<?>) listParameter); }
Looks up the appropriate FieldType by it's identifier.
Returns:the FieldType or null if not found.
/** * Looks up the appropriate {@link FieldType} by it's identifier. * * @return the {@link FieldType} or {@code null} if not found. */
/* @Nullable */ public static FieldType forId(int id) { if (id < 0 || id >= VALUES.length) { return null; } return VALUES[id]; } private static final FieldType[] VALUES; private static final Type[] EMPTY_TYPES = new Type[0]; static { FieldType[] values = values(); VALUES = new FieldType[values.length]; for (FieldType type : values) { VALUES[type.id] = type; } }
Given a class, finds a generic super class or interface that extends List.
Returns:the generic super class/interface, or null if not found.
/** * Given a class, finds a generic super class or interface that extends {@link List}. * * @return the generic super class/interface, or {@code null} if not found. */
/* @Nullable */ private static Type getGenericSuperList(Class<?> clazz) { // First look at interfaces. Type[] genericInterfaces = clazz.getGenericInterfaces(); for (Type genericInterface : genericInterfaces) { if (genericInterface instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericInterface; Class<?> rawType = (Class<?>) parameterizedType.getRawType(); if (List.class.isAssignableFrom(rawType)) { return genericInterface; } } } // Try the subclass Type type = clazz.getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Class<?> rawType = (Class<?>) parameterizedType.getRawType(); if (List.class.isAssignableFrom(rawType)) { return type; } } // No super class/interface extends List. return null; }
Inspects the inheritance hierarchy for the given class and finds the generic type parameter for List.
Params:
  • clazz – the class to begin the search.
  • realTypes – the array of actual type parameters for clazz. These will be used to substitute generic parameters up the inheritance hierarchy. If clazz does not have any generic parameters, this list should be empty.
Returns:the List parameter.
/** * Inspects the inheritance hierarchy for the given class and finds the generic type parameter for * {@link List}. * * @param clazz the class to begin the search. * @param realTypes the array of actual type parameters for {@code clazz}. These will be used to * substitute generic parameters up the inheritance hierarchy. If {@code clazz} does not have * any generic parameters, this list should be empty. * @return the {@link List} parameter. */
private static Type getListParameter(Class<?> clazz, Type[] realTypes) { top: while (clazz != List.class) { // First look at generic subclass and interfaces. Type genericType = getGenericSuperList(clazz); if (genericType instanceof ParameterizedType) { // Replace any generic parameters with the real values. ParameterizedType parameterizedType = (ParameterizedType) genericType; Type[] superArgs = parameterizedType.getActualTypeArguments(); for (int i = 0; i < superArgs.length; ++i) { Type superArg = superArgs[i]; if (superArg instanceof TypeVariable) { // Get the type variables for this class so that we can match them to the variables // used on the super class. TypeVariable<?>[] clazzParams = clazz.getTypeParameters(); if (realTypes.length != clazzParams.length) { throw new RuntimeException("Type array mismatch"); } // Replace the variable parameter with the real type. boolean foundReplacement = false; for (int j = 0; j < clazzParams.length; ++j) { if (superArg == clazzParams[j]) { Type realType = realTypes[j]; superArgs[i] = realType; foundReplacement = true; break; } } if (!foundReplacement) { throw new RuntimeException("Unable to find replacement for " + superArg); } } } Class<?> parent = (Class<?>) parameterizedType.getRawType(); realTypes = superArgs; clazz = parent; continue; } // None of the parameterized types inherit List. Just continue up the inheritance hierarchy // toward the List interface until we can identify the parameters. realTypes = EMPTY_TYPES; for (Class<?> iface : clazz.getInterfaces()) { if (List.class.isAssignableFrom(iface)) { clazz = iface; continue top; } } clazz = clazz.getSuperclass(); } if (realTypes.length != 1) { throw new RuntimeException("Unable to identify parameter type for List<T>"); } return realTypes[0]; } enum Collection { SCALAR(false), VECTOR(true), PACKED_VECTOR(true), MAP(false); private final boolean isList; Collection(boolean isList) { this.isList = isList; }
Returns:the isList
/** @return the isList */
public boolean isList() { return isList; } } }