我通过使用 Java 反射调用来获取相关的内部成员解决了这个问题。这其中的关键部分是对象setAccessible
上的功能Field
。此函数关闭 Field 对象的访问控制,允许公共访问,尽管不是通过普通语法。(注意实际的函数名称;它不是subvertAccessControls
.) 此调用在普通 JRE 环境中成功,并且可能无法在例如 applet 中工作。我没有费心检查这个,因为这是一个开发工具来检查原生类型的拖动事件,因为 (1) 应用程序不知道原生类型和 (2) 没有数据将本机数据传输转换为 Java 对象。因此,对于每个具有拖动类型的应用程序,我只需要它运行一次,我是逆向工程;我只需要在普通的 JRE 中运行。
谢天谢地,我不必突破java.lang.instrument
甚至 JVMTI。然而,我确实不得不滥用安全系统。
测试代码片段如下。变量long native_types[]
是输出。DropTargetDragEvent dtde
是输入;它是事件处理程序的参数。
long native_types[];
try {
/*
* Retrieve the drop target context.
*
* We can retrieve this member directly, because it's a public field.
*/
DropTargetContext dtc = ( ( DropTarget ) dtde.getSource() ).getDropTargetContext();
/*
* Retrieve the drop target context peer.
*
* We cannot retrieve this member without reflection, because it's a private field. We get the class
* object from the public class declaration. The field "dropTargetContextPeer" is private, so we
* have to retrieve with a reflection call and then set it to be accessible so that we don't get
* IllegalAccessException when we call get() on the field. Since we're only going to use reflection
* on the drop target context peer, we don't bother trying to cast it and just leave it declared
* as Object.
*/
Class<DropTargetContext> DTC_class = DropTargetContext.class;
Field DTCP_field = DTC_class.getDeclaredField( "dropTargetContextPeer" );
DTCP_field.setAccessible( true );
Object dtcp = DTCP_field.get( dtc );
/*
* Retrieve the array of native types.
*
* This is almost exactly analogous to the previous retrieval, but with the exception that the field
* is defined in the superclass, not the class itself. Because the field is declared private, we can't
* simply use getField(), since that only works on public fields. So we get the class object for the
* parent class and proceed as before.
*
* As a bonus, this routine is cross-platform. The class sun.awt.windows.WDropTargetContextPeer is
* the implementation class for sun.awt.dnd.SunDropTargetContextPeer for Windows. The type identifiers,
* though, all fit into a long for every platform.
*/
Class<?> DTCP_class = dtcp.getClass();
Class<?> DTCP_superclass = DTCP_class.getSuperclass();
Field CT_field = DTCP_superclass.getDeclaredField( "currentT" );
CT_field.setAccessible( true );
native_types = ( long[] ) CT_field.get( dtcp );
} catch ( Exception e ) {
throw new RuntimeException( "Did not retrieve native types.", e );
}