/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.baidu.bjf.remoting.protobuf.utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.baidu.bjf.remoting.protobuf.annotation.Protobuf;
/**
* Field utility class.
*
* @author xiemalin
* @since 1.0.0
*/
public final class FieldUtils {
private static final Map<String, String> PRIMITIVE_TYPE_MAPPING;
static {
PRIMITIVE_TYPE_MAPPING = new HashMap<String, String>();
PRIMITIVE_TYPE_MAPPING.put(int.class.getSimpleName(), Integer.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(long.class.getSimpleName(), Long.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(short.class.getSimpleName(), Short.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(boolean.class.getSimpleName(), Boolean.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(double.class.getSimpleName(), Double.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(float.class.getSimpleName(), Float.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(char.class.getSimpleName(), Character.class.getSimpleName());
PRIMITIVE_TYPE_MAPPING.put(byte.class.getSimpleName(), Byte.class.getSimpleName());
}
/**
* Logger for this class
*/
private static final Logger LOGGER = Logger.getLogger(FieldUtils.class.getName());
public static String toObjectType(String primitiveType) {
if (PRIMITIVE_TYPE_MAPPING.containsKey(primitiveType)) {
return PRIMITIVE_TYPE_MAPPING.get(primitiveType);
}
return ClassHelper.getInternalName(primitiveType);
}
/**
* Get the field represented by the supplied {@link Field field object} on
* the specified {@link Object target object}. In accordance with
* {@link Field#get(Object)} semantics, the returned value is automatically
* wrapped if the underlying field has a primitive type.
* <p>
* Thrown exceptions are handled via a call to
*
* @param t
* the target object from which to get the field
* @param name
* the field to get
* @return the field's current value
*/
public static Object getField(Object t, String name) {
Field field = findField(t.getClass(), name);
if (field == null) {
return null;
}
field.setAccessible(true);
try {
return field.get(t);
} catch (Exception e) {
LOGGER.log(Level.FINE, e.getMessage(), e);
}
return null;
}
/**
* Set the field represented by the supplied {@link Field field object} on
* the specified {@link Object target object} to the specified
* <code>value</code>. In accordance with {@link Field#set(Object, Object)}
* semantics, the new value is automatically unwrapped if the underlying
* field has a primitive type.
* <p>
* Thrown exceptions are handled via a call to
*
* @param t
* the target object on which to set the field
* @param name
* the field to set
* @param value
* the value to set; may be <code>null</code>
*/
public static void setField(Object t, String name, Object value) {
Field field = findField(t.getClass(), name);
if (field == null) {
return;
}
field.setAccessible(true);
try {
field.set(t, value);
} catch (Exception e) {
LOGGER.log(Level.FINE, e.getMessage(), e);
}
}
/**
* Attempt to find a {@link Field field} on the supplied {@link Class} with
* the supplied <code>name</code>. Searches all superclasses up to
* {@link Object}.
*
* @param clazz
* the class to introspect
* @param name
* the name of the field
* @return the corresponding Field object, or <code>null</code> if not found
*/
public static Field findField(Class clazz, String name) {
return findField(clazz, name, null);
}
/**
* Attempt to find a {@link Field field} on the supplied {@link Class} with
* the supplied <code>name</code> and/or {@link Class type}. Searches all
* superclasses up to {@link Object}.
*
* @param clazz
* the class to introspect
* @param name
* the name of the field (may be <code>null</code> if type is
* specified)
* @param type
* the type of the field (may be <code>null</code> if name is
* specified)
* @return the corresponding Field object, or <code>null</code> if not found
*/
public static Field findField(Class clazz, String name, Class type) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (name == null && type == null) {
throw new IllegalArgumentException(
"Either name or type of the field must be specified");
}
Class searchType = clazz;
while (!Object.class.equals(searchType) && searchType != null) {
Field[] fields = searchType.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if ((name == null || name.equals(field.getName()))
&& (type == null || type.equals(field.getType()))) {
return field;
}
}
searchType = searchType.getSuperclass();
}
return null;
}
/**
* To find out matched {@link Field} marked as {@link Protobuf} annotation
*
* @param targetClass taget class
* @return found {@link Field} list
*/
public static List<Field> findMatchedFields(Class targetClass, Class ann) {
List<Field> ret = new ArrayList<Field>();
if (targetClass == null) {
return ret;
}
// Keep backing up the inheritance hierarchy.
do {
// Copy each field declared on this class unless it's static or
// file.
Field[] fields = targetClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Annotation protobuf = fields[i].getAnnotation(ann);
if (protobuf != null) {
ret.add(fields[i]);
}
}
targetClass = targetClass.getSuperclass();
} while (targetClass != null && targetClass != Object.class);
return ret;
}
}