/* * Copyright 2010 Google Inc. * * 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.google.gwt.user.client.rpc.impl; import com.google.gwt.dev.util.Pair; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.LinkedHashMap; /** * Provides access to reflection capability, but only when running from * bytecode. */ public class ReflectionHelper { // Only used from single-threaded JS. Doesn't need to be thread-safe. private static class Cache<K, V extends AccessibleObject> extends LinkedHashMap<K, V> { private static final int MAX_SIZE = 1024; // These values lifted from defaults. private static final int INITIAL_CAPACITY = 16; private static final float LOAD_FACTOR = 0.75f; public Cache() { super(INITIAL_CAPACITY, LOAD_FACTOR, true); } @Override protected boolean removeEldestEntry( java.util.Map.Entry<K, V> eldest) { return size() > MAX_SIZE; } } private static final Cache<Class<?>, Constructor<?>> constructorCache = new Cache<Class<?>, Constructor<?>>(); private static final Cache<Pair<Class<?>,String>, Field> fieldCache = new Cache<Pair<Class<?>,String>, Field>(); private static Field findField(Class<?> klass, String name) { Pair<Class<?>, String> key = Pair.<Class<?>,String>create(klass, name); Field f = fieldCache.get(key); if (f == null) { try { f = klass.getDeclaredField(name); } catch (NoSuchFieldException ex) { throw new RuntimeException( "Unable to find field " + klass.getName() + "." + name, ex); } f.setAccessible(true); fieldCache.put(key, f); } return f; } /** * Gets the value of a field. */ public static Object getField(Class<?> klass, Object obj, String name) { Field f = findField(klass, name); try { return f.get(obj); } catch (IllegalAccessException ex) { throw new RuntimeException("Unexpected failure", ex); } } /** * Loads {@code klass} using Class.forName. */ public static Class<?> loadClass(String klass) { try { return Class.forName(klass); } catch (ClassNotFoundException ex) { throw new RuntimeException("Unable to find class " + klass, ex); } } /** * Creates a new instance of {@code klass}. The class must have a no-arg * constructor. The constructor may have any access modifier (for example, * private). */ @SuppressWarnings("unchecked") public static <T> T newInstance(Class<T> klass) { Constructor<T> c = (Constructor<T>) constructorCache.get(klass); try { if (c == null) { c = klass.getDeclaredConstructor(); c.setAccessible(true); constructorCache.put(klass, c); } return c.newInstance(); } catch (Exception ex) { throw new RuntimeException("Unexpected failure", ex); } } /** * Sets the value of a field. */ public static void setField(Class<?> klass, Object obj, String name, Object value) throws Exception { Field f = findField(klass, name); try { f.set(obj, value); } catch (IllegalAccessException ex) { throw new RuntimeException("Unexpected failure", ex); } } }