org.springsource.loaded.ri.FieldLookup Maven / Gradle / Ivy
/*
* 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 getFields() {
Field[] fields = clazz.getDeclaredFields();
List refs = new ArrayList();
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 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 getFields() {
FieldMember[] fields = rtype.getLatestTypeDescriptor().getFields();
List refs = new ArrayList(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;
}
}
}