java.lang.ClassCastException 关于代理创建
java.lang.ClassCastException on Proxy creation
我的目标是从实现 interface
的 class
创建实例并扩展另一个 class
.
...实体注释:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Entity {
String visibileName();
}
...实施IEventDesignDialog
public class EventDesignDialog implements IEventDesignDialog{
private String show;
private String dateAndTimeDisplayFormat;
private String eventType;
@Entity(visibileName = "Show")
public String getShow() {
return this.show;
}
@Entity(visibileName = "Date And Time display format")
public String getDateAndTimeDisplayFormat() {
return this.dateAndTimeDisplayFormat;
}
@Entity(visibileName = "Event Type")
public String getEventType() {
System.out.println("get event type method invokde successfully");
return this.eventType;
}
}
IEventDesignDialog
接口:
public interface IEventDesignDialog extends IPage{
public String getShow();
public String getDateAndTimeDisplayFormat();
public String getEventType();
}
IPage
接口:
public interface IPage {
}
动态代理实现:
public class IPageProxy implements InvocationHandler {
private List<Method> entityMethods;
private Class <? extends IPage> screenClazz;
public IPageProxy(final Class <? extends IPage> screenClazz) {
entityMethods = new ArrayList<>();
getEntityAnnotatedMethods(screenClazz);
// Accept the real implementation to be proxied
this.screenClazz = screenClazz;
}
/**
* create an page instance
* @param type
* @param
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
public static IPage getInstance(final Class<? extends IPage> type)
throws InstantiationException, IllegalAccessException {
List<Class<?>> interfaces = new ArrayList<>();
interfaces.addAll(Arrays.asList(type.getInterfaces()));
return (IPage) Proxy.newProxyInstance(
type.getClassLoader(),
findInterfaces(type),
new IPageProxy(type)
);
/*return (IPage) Proxy.newProxyInstance(type.getClassLoader(),
interfaces.toArray(new Class<?>[interfaces.size()])
, new IPageProxy(type));*/
}
/**
* get all methods that annotated with @Entity annotation
* and add it for entityMethods array List
* @param screenClazz
*/
private void getEntityAnnotatedMethods(final Class <? extends IPage> screenClazz) {
// Scan each interface method for the specific annotation
// and save each compatible method
for (final Method m : screenClazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(Entity.class)) {
entityMethods.add(m);
}
}
}
static Class<?>[] findInterfaces(final Class<? extends IPage> type) {
Class<?> current = type;
do {
final Class<?>[] interfaces = current.getInterfaces();
if (interfaces.length != 0) {
return interfaces;
}
} while ((current = current.getSuperclass()) != Object.class);
throw new UnsupportedOperationException("The type does not implement any interface");
}
@Override
public Object invoke(
final Object proxy,
final Method method,
final Object[] args) throws InvocationTargetException, IllegalAccessException {
// A method on MyInterface has been called!
// Check if we need to go call it directly or if we need to
// execute something else before!
if (entityMethods.contains(method)) {
// The method exist in our to-be-proxied list
// Execute something and the call it
// ... some other things
System.out.println("Something else");
}
// Invoke original method
return method.invoke(screenClazz, args);
}
}
主要class:
public class Main {
public static void main(String[] args) {
try {
((EventDesignDialog)getInstance(EventDesignDialog.class)).getEventType();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static <T extends IPage> T getInstance(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {
return (T) IPageProxy.getInstance(type);
}
}
抛出以下异常:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy2 cannot be cast to abc.EventDesignDialog
at abc.Main.main(Main.java:8)
您正在 扩展 Screen
,这意味着它不是 interface
。
仅当层次结构中存在基础 interface
时,动态代理才有效。
interfaces.size() == 0
因此代理无法实现任何 interface
,显然它不是 Screen
层次结构的一部分。
如果 Screen
是 interface
,你的方法还是太复杂了。这个
public static Screen getInstance(Class<? extends Screen> type)
足够了。
您仍然收到异常,因为
Class#getInterfaces
returns 由 this class.
实现的 interface
s
这意味着如果您在 EventDesignDialog.class
上调用它,它将 return 一个空数组。
这意味着如果你在 EntityDesignDialog.class
上调用它,它仍然会 return 一个空数组。
在 Screen.class
上调用它时,它将 return
[IPage.class]
您需要使用
循环层次结构
Class#getSuperclass
直到找到合适的interface
。
一个可能的实现可能看起来像
static Class<?>[] findInterfaces(final Class<?> type) {
Class<?> current = type;
do {
final Class<?>[] interfaces = current.getInterfaces();
if (interfaces.length != 0) {
return interfaces;
}
} while ((current = current.getSuperclass()) != Object.class);
throw new UnsupportedOperationException("The type does not implement any interface");
}
这意味着您需要将代码更改为
return (IPage) Proxy.newProxyInstance(
type.getClassLoader(),
findInterfaces(type),
new IPageProxy(type)
);
但是,由于您已经知道结果将是 IPage
代理,您可以
return (IPage) Proxy.newProxyInstance(
type.getClassLoader(),
new Class[] { IPage.class },
new IPageProxy(type)
);
这里
public static IPage getInstance(final Class<? extends IPage> type)
您正在 returnIPage
,但这里
((EventDesignDialog)getInstance(EventDesignDialog.class))
您正在尝试 向下转换 它,这意味着您正在尝试将其转换为更具体的类型。这是不可能的,因为代理不是 EventDesignDialog
类型,但它只是实现了您的 IPage
接口。
由于动态代理是基于接口的,您将被迫处理接口。
尝试转换为具体的 classes 总是会抛出异常。
如果您需要 IEventDesignDialog
,您需要一个专门用于它的新代理。
我的目标是从实现 interface
的 class
创建实例并扩展另一个 class
.
...实体注释:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Entity {
String visibileName();
}
...实施IEventDesignDialog
public class EventDesignDialog implements IEventDesignDialog{
private String show;
private String dateAndTimeDisplayFormat;
private String eventType;
@Entity(visibileName = "Show")
public String getShow() {
return this.show;
}
@Entity(visibileName = "Date And Time display format")
public String getDateAndTimeDisplayFormat() {
return this.dateAndTimeDisplayFormat;
}
@Entity(visibileName = "Event Type")
public String getEventType() {
System.out.println("get event type method invokde successfully");
return this.eventType;
}
}
IEventDesignDialog
接口:
public interface IEventDesignDialog extends IPage{
public String getShow();
public String getDateAndTimeDisplayFormat();
public String getEventType();
}
IPage
接口:
public interface IPage {
}
动态代理实现:
public class IPageProxy implements InvocationHandler {
private List<Method> entityMethods;
private Class <? extends IPage> screenClazz;
public IPageProxy(final Class <? extends IPage> screenClazz) {
entityMethods = new ArrayList<>();
getEntityAnnotatedMethods(screenClazz);
// Accept the real implementation to be proxied
this.screenClazz = screenClazz;
}
/**
* create an page instance
* @param type
* @param
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
public static IPage getInstance(final Class<? extends IPage> type)
throws InstantiationException, IllegalAccessException {
List<Class<?>> interfaces = new ArrayList<>();
interfaces.addAll(Arrays.asList(type.getInterfaces()));
return (IPage) Proxy.newProxyInstance(
type.getClassLoader(),
findInterfaces(type),
new IPageProxy(type)
);
/*return (IPage) Proxy.newProxyInstance(type.getClassLoader(),
interfaces.toArray(new Class<?>[interfaces.size()])
, new IPageProxy(type));*/
}
/**
* get all methods that annotated with @Entity annotation
* and add it for entityMethods array List
* @param screenClazz
*/
private void getEntityAnnotatedMethods(final Class <? extends IPage> screenClazz) {
// Scan each interface method for the specific annotation
// and save each compatible method
for (final Method m : screenClazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(Entity.class)) {
entityMethods.add(m);
}
}
}
static Class<?>[] findInterfaces(final Class<? extends IPage> type) {
Class<?> current = type;
do {
final Class<?>[] interfaces = current.getInterfaces();
if (interfaces.length != 0) {
return interfaces;
}
} while ((current = current.getSuperclass()) != Object.class);
throw new UnsupportedOperationException("The type does not implement any interface");
}
@Override
public Object invoke(
final Object proxy,
final Method method,
final Object[] args) throws InvocationTargetException, IllegalAccessException {
// A method on MyInterface has been called!
// Check if we need to go call it directly or if we need to
// execute something else before!
if (entityMethods.contains(method)) {
// The method exist in our to-be-proxied list
// Execute something and the call it
// ... some other things
System.out.println("Something else");
}
// Invoke original method
return method.invoke(screenClazz, args);
}
}
主要class:
public class Main {
public static void main(String[] args) {
try {
((EventDesignDialog)getInstance(EventDesignDialog.class)).getEventType();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static <T extends IPage> T getInstance(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {
return (T) IPageProxy.getInstance(type);
}
}
抛出以下异常:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy2 cannot be cast to abc.EventDesignDialog
at abc.Main.main(Main.java:8)
您正在 扩展 Screen
,这意味着它不是 interface
。
仅当层次结构中存在基础 interface
时,动态代理才有效。
interfaces.size() == 0
因此代理无法实现任何 interface
,显然它不是 Screen
层次结构的一部分。
如果 Screen
是 interface
,你的方法还是太复杂了。这个
public static Screen getInstance(Class<? extends Screen> type)
足够了。
您仍然收到异常,因为
Class#getInterfaces
returns 由 this class.
实现的interface
s
这意味着如果您在 EventDesignDialog.class
上调用它,它将 return 一个空数组。
这意味着如果你在 EntityDesignDialog.class
上调用它,它仍然会 return 一个空数组。
在 Screen.class
上调用它时,它将 return
[IPage.class]
您需要使用
循环层次结构Class#getSuperclass
直到找到合适的interface
。
一个可能的实现可能看起来像
static Class<?>[] findInterfaces(final Class<?> type) {
Class<?> current = type;
do {
final Class<?>[] interfaces = current.getInterfaces();
if (interfaces.length != 0) {
return interfaces;
}
} while ((current = current.getSuperclass()) != Object.class);
throw new UnsupportedOperationException("The type does not implement any interface");
}
这意味着您需要将代码更改为
return (IPage) Proxy.newProxyInstance(
type.getClassLoader(),
findInterfaces(type),
new IPageProxy(type)
);
但是,由于您已经知道结果将是 IPage
代理,您可以
return (IPage) Proxy.newProxyInstance(
type.getClassLoader(),
new Class[] { IPage.class },
new IPageProxy(type)
);
这里
public static IPage getInstance(final Class<? extends IPage> type)
您正在 returnIPage
,但这里
((EventDesignDialog)getInstance(EventDesignDialog.class))
您正在尝试 向下转换 它,这意味着您正在尝试将其转换为更具体的类型。这是不可能的,因为代理不是 EventDesignDialog
类型,但它只是实现了您的 IPage
接口。
由于动态代理是基于接口的,您将被迫处理接口。
尝试转换为具体的 classes 总是会抛出异常。
如果您需要 IEventDesignDialog
,您需要一个专门用于它的新代理。