/* * Copyright 2010-2012 VMware and contributors * * 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 org.springsource.loaded.ri; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Type; import org.springsource.loaded.CurrentLiveVersion; import org.springsource.loaded.FieldMember; import org.springsource.loaded.GlobalConfiguration; import org.springsource.loaded.ReloadableType; import org.springsource.loaded.TypeRegistry; import org.springsource.loaded.Utils; import org.springsource.loaded.jvm.JVM; /** * This class contains code that is used as support infrastructure to implement Field lookup algorithms. * * Mainly, it provides an abstraction to allows Java classes and reloadable types to be treated as instances of a common * abstraction "FieldProvider" and then implement algorithms to find fields in those providers independent of how the * fields are being provided. * * @author Kris De Volder * @since 0.5.0 */ public class FieldLookup { private static class JavaFieldRef extends FieldRef { private Field f; public JavaFieldRef(Field f) { this.f = f; } @Override public Field getField() { return f; } @Override public String getName() { return f.getName(); } @Override public boolean isPublic() { return Modifier.isPublic(f.getModifiers()); } } private static class JavaClassFieldProvider extends FieldProvider { private Class<?> clazz; public JavaClassFieldProvider(Class<?> clazz) { this.clazz = clazz; } @Override List<FieldRef> getFields() { Field[] fields = clazz.getDeclaredFields(); List<FieldRef> refs = new ArrayList<FieldLookup.FieldRef>(); for (Field f : fields) { refs.add(new JavaFieldRef(f)); } return refs; } @Override public boolean isInterface() { return clazz.isInterface(); } @Override public FieldProvider[] getInterfaces() { Class<?>[] itfs = clazz.getInterfaces(); FieldProvider[] provs = new FieldProvider[itfs.length]; for (int i = 0; i < itfs.length; i++) { provs[i] = FieldProvider.create(itfs[i]); } return provs; } @Override public FieldProvider getSuper() { Class<?> supr = clazz.getSuperclass(); if (supr != null) { FieldProvider.create(supr); } return null; } } static abstract class FieldRef { public abstract Field getField(); public abstract String getName(); public abstract boolean isPublic(); } public static class ReloadedTypeFieldRef extends FieldRef { private ReloadableType rtype; private FieldMember f; public ReloadedTypeFieldRef(ReloadableType rtype, FieldMember f) { if (GlobalConfiguration.assertsMode) { Utils.assertTrue(rtype.hasBeenReloaded(), "Not yet reloaded: " + rtype.getName()); } this.rtype = rtype; this.f = f; } @Override public Field getField() { Class<?> declaring = Utils.toClass(rtype); Class<?> type; try { type = Utils.toClass(Type.getType(f.getDescriptor()), rtype.typeRegistry.getClassLoader()); } catch (ClassNotFoundException e) { throw new IllegalStateException(e); } return JVM.newField(declaring, type, f.getModifiers(), f.getName(), f.getGenericSignature()); } @Override public String getName() { return f.getName(); } @Override public boolean isPublic() { return f.isPublic(); } } protected static abstract class FieldProvider { abstract List<FieldRef> getFields(); public abstract boolean isInterface(); public abstract FieldProvider[] getInterfaces(); public abstract FieldProvider getSuper(); public static FieldProvider create(ReloadableType rtype) { return new ReloadableTypeFieldProvider(rtype); } public static FieldProvider create(TypeRegistry typeRegistry, String slashyName) { if (typeRegistry.isReloadableTypeName(slashyName)) { return create(typeRegistry.getReloadableType(slashyName)); } else { try { return create(Utils.toClass(Type.getObjectType(slashyName), typeRegistry.getClassLoader())); } catch (ClassNotFoundException e) { throw new IllegalStateException(e); } } } public static FieldProvider create(Class<?> clazz) { return new JavaClassFieldProvider(clazz); } } public static class ReloadableTypeFieldProvider extends FieldProvider { private ReloadableType rtype; public ReloadableTypeFieldProvider(ReloadableType rtype) { this.rtype = rtype; } @Override List<FieldRef> getFields() { FieldMember[] fields = rtype.getLatestTypeDescriptor().getFields(); List<FieldRef> refs = new ArrayList<FieldRef>(fields.length); for (FieldMember f : fields) { refs.add(fieldRef(rtype, f)); } return refs; } private FieldRef fieldRef(ReloadableType rtype, FieldMember f) { CurrentLiveVersion clv = rtype.getLiveVersion(); if (clv == null) { //Not yet reloaded... use original field (with fixed mods) try { Field jf = rtype.getClazz().getDeclaredField(f.getName()); ReflectiveInterceptor.fixModifier(rtype.getLatestTypeDescriptor(), jf); return new JavaFieldRef(jf); } catch (Exception e) { throw new IllegalStateException(e); } } else { //Already reloaded return new ReloadedTypeFieldRef(rtype, f); } } @Override public boolean isInterface() { return rtype.getLatestTypeDescriptor().isInterface(); } @Override public FieldProvider[] getInterfaces() { String[] superItfs = rtype.getLatestTypeDescriptor().getSuperinterfacesName(); FieldProvider[] superProvs = new FieldProvider[superItfs.length]; for (int i = 0; i < superItfs.length; i++) { superProvs[i] = FieldProvider.create(rtype.typeRegistry, superItfs[i]); } return superProvs; } @Override public FieldProvider getSuper() { String supr = rtype.getLatestTypeDescriptor().getSupertypeName(); if (supr != null) { return FieldProvider.create(rtype.typeRegistry, supr); } return null; } } }