I was trying to learn reflection and I came across this IllegalAccessException. Please see the following code:
public class ReflectionTest
{
public static void main(String[] args)
{
Set<String> myStr = new HashSet<String>();
myStr.add("obj1");
Iterator itr = myStr.iterator();
Method mtd = itr.getClass().getMethod("hasNext");
System.out.println(m.invoke(it));
}
}
When I tried to run this program, I got the following:
Exception in thread "main" IllegalAccessException
I don't understand what's going on. Any ideas? Thanks in advance.
The troublesome piece of code is this:
itr.getClass().getMethod
You probably wanted hasNext on the Iterator class. What you have written is the HashMap.KeyIterator class, which according the Java language access specifiers (or at least the rough interpretation of JDK 1.0 used by reflection) is not available to your code.
Use instead:
Iterator.class.getMethod
(And if it wasn't for learning purposes, stay away from reflection.)
You cannot access it, because the Iterator is a private inner class. More explanation can be found here.
It's apparent that your currently executing method does not have access to the method named hasNext, e.g., by it being private or protected. You could try to enable access to it using method.setAccessible(true);
It might also be that you have some restrictions defined in your security manager (which, if you use e.g., linux, might have been included default from the distributions java package).
[EDIT] As it turns out, Tom Hawtin identified the correct root cause. You are indeed operating on HashMap.KeyIterator. Although the solution would be to use Iterator.class instead of itr.getClass() you could still enable access to it using setAccessible(true).
I suspect you should use getDeclaredMethod (among other issues). I don't bother to remember Reflection API details (they're for the compiler!), but in your case compare your code with that produced by dp4j:
$ javac -Averbose=true -All -cp dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar ReflectionTest.java
ReflectionTest.java:6: Note:
import java.util.*;
public class ReflectionTest {
public ReflectionTest() {
super();
}
#com.dp4j.Reflect()
public static void main(String[] args) throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.InstantiationException, java.lang.IllegalArgumentException {
final java.lang.reflect.Constructor hashSetConstructor = Class.forName("java.util.HashSet").getDeclaredConstructor();
hashSetConstructor.setAccessible(true);
Set<String> myStr = (.java.util.Set<.java.lang.String>)hashSetConstructor.newInstance();
final java.lang.reflect.Method addWithEMethod = Class.forName("java.util.Set").getDeclaredMethod("add", .java.lang.Object.class);
addWithEMethod.setAccessible(true);
addWithEMethod.invoke(myStr, new .java.lang.Object[1][]{"obj1"});
final java.lang.reflect.Method iteratorMethod = Class.forName("java.util.Set").getDeclaredMethod("iterator");
iteratorMethod.setAccessible(true);
Iterator itr = (.java.util.Iterator)iteratorMethod.invoke(myStr);
final java.lang.reflect.Method hasNextMethod = Class.forName("java.util.Iterator").getDeclaredMethod("hasNext");
hasNextMethod.setAccessible(true);
final java.lang.reflect.Method printlnWithbooleanMethod = Class.forName("java.io.PrintStream").getDeclaredMethod("println", .java.lang.Boolean.TYPE);
printlnWithbooleanMethod.setAccessible(true);
printlnWithbooleanMethod.invoke(System.out, new .java.lang.Object[1][]{hasNextMethod.invoke(itr)});
}
}
public static void main(String[] args)
^
...
$ java ReflectionTest
true
The only change you need to do is annotate your main method with #com.dp4j.Reflect:
$ vim ReflectionTest.java
import java.util.*;
public class ReflectionTest
{
#com.dp4j.Reflect
public static void main(String[] args)
{
Set<String> myStr = new HashSet<String>();
myStr.add("obj1");
Iterator itr = myStr.iterator();
// Method mtd = itr.getClass().getMethod("hasNext");
System.out.println(itr.hasNext());
}
}
NB: this works only with dp4j-1.2-SNAPSHOT (I've just added suport for it). If you don't use Maven, download the jar from here. You find the test case with your problem here.
Related
I am currently executing my JavaScript-scripts with this java code:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("awesome_script.js"));
I need to call Java functions from JavaScript, so I defined this at the top of my awesome_script.js file:
var first = Java.type('io.github.awesomeprogram.FirstClass');
var second = Java.type('io.github.awesomeprogram.SecondClass');
var extra = Java.type('io.github.awesomeprogram.ExtraClass');
I can then call some methods from these classes, e.g.:
second.coolmethod("arg1",2);
My problem is now that I need to use many java classes inside of my scripts. I also have a lot of scripts and I think it is very inefficient to define every single one of this classes in every script.
So I am looking for a solution to create the objects created inside of JavaScript with Java.type() inside of Java and then pass them to the script I want to execute.
How can I do this?
Thanks in advance!
You may want to avoid using the "internal" classes in packages like "jdk.internal.", "jdk.nashorn.internal.". In jdk9, dynalink is an API ("jdk.dynalink" has exported packages). In jdk9, you can call jdk.dyanlink.beans.StaticClass.forClass(Class) [ http://download.java.net/java/jdk9/docs/jdk/api/dynalink/jdk/dynalink/beans/StaticClass.html#forClass-java.lang.Class- ] to construct "type" objects and expose those as global variables to the script engine. For jdk8, you could pre-eval a script that uses Java.type(String) calls before evaluating "user" scripts. You can also call "Java.type" function from Java code.
Solution for jdk9:
import jdk.dynalink.beans.StaticClass;
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
e.put("AList", StaticClass.forClass(java.util.ArrayList.class));
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
Solution for jdk8:
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// eval a "boot script" before evaluating user script
// Note that this script could come from your app resource URL
e.eval("var AList = Java.type('java.util.ArrayList')");
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
Alternative solution for jdk8:
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// get Java.type function as object
JSObject javaTypeFunc = (JSObject) e.eval("Java.type");
// you can javaTypeFunc from java code many times
Object alType = javaTypeFunc.call(null, "java.util.ArrayList");
// expose that as global
e.put("AList", alType);
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
After quite a bit of research I found a way to put global variables in the ScriptEngine before executing: The Java Scripting API (Oracle Docs)
This enabled me to put any object I want into a global variable. However, I still needed a way to get the Object that Java.type() creates inside of Java. So I wrote a test script which returns one of this objects and I found out it is an object of the type jdk.internal.dynalink.beans.StaticClass. This class has an constructor which takes a ordinary Class as an argument. Sadly, this constructor is not usable in my code because it is not visible. To bypass this I used reflection and made this method:
public StaticClass toNashornClass(Class<?> c) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class<?> cl = Class.forName("jdk.internal.dynalink.beans.StaticClass");
Constructor<?> constructor = cl.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
StaticClass o = (StaticClass) constructor.newInstance(c);
return o;
}
If I pass the Class of the object I want as a global variable I just need to call toNashornClass(Example.class); and put the resulting object into a global var with engine.put("example",object);
It works fine. I can use the example var completely like a var created by Java.type().
I'm trying to work with this enum and add new materials.
Anything not already removed has hard dependencies elsewhere, even still, this is nearly at the java byte limit according to the mods author so there isn't really a lot of room to work with anyway.
GregoriousT mentioned "There is one way. Overmind hacked the Enum using Reflection to add his own stuff. No Idea how he did that and also no idea how long he takes to reply to things if you ask him."
Enum we're talking about:
http://pastebin.com/g0aJ2Qjd
So I simply ask, how would I go about this?
This is what my current attempt throws [FML]: Variable m:1|newInstance|public java.lang.Object sun.reflect.DelegatingConstructorAccessorImpl.newInstance(java.lang.Object[]) throws java.lang.InstantiationException,java.lang.IllegalArgumentException,java.lang.reflect.InvocationTargetException|false
before the client crashes. (Log code removed for easy reading)
Current attempt:
public class MaterialsNew {
public static void getGregMaterials() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException{
Utils.LOG_WARNING("Stepping through the process of Greg's materials.");
Constructor<?> con = Materials.class.getDeclaredConstructors()[0];
java.lang.reflect.Method[] methods = con.getClass().getDeclaredMethods();
for (java.lang.reflect.Method m1 : methods) {
if (m1.getName().equals("acquireConstructorAccessor")) {
m1.setAccessible(true);
m1.invoke(con, new Object[0]);}
}
Field[] fields = con.getClass().getDeclaredFields();
Object ca = null;
for (Field f : fields) {
if (f.getName().equals("constructorAccessor")) {
f.setAccessible(true);
ca = f.get(con);
}
}
Method m = ca.getClass().getMethod( "newInstance", new Class[] { Object[].class });
m.setAccessible(true);
Materials v = (Materials) m.invoke(ca, new Object[] { new Object[] { "NEWMATERIAL", Integer.MAX_VALUE } });
System.out.println(v.getClass() + ":" + v.name() + ":" + v.ordinal());}}
Any help or suggestions appreciated, they guys over at the Forge IRC weren't really sure either.
JVMs are supposed to prevent such sneaky enum instance creations. So you have to either use a flaw that soon might get solved or hack such deep into the JRE that the slightest change may break it.
Here is a trick which works with Oracle’s current JRE 8, perhaps JRE 7 as well, and is surprisingly simple:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.util.EnumSet;
public class EnumHack {
public static void main(String[] args) throws Throwable {
Constructor<Thread.State> c
= Thread.State.class.getDeclaredConstructor(String.class, int.class);
c.setAccessible(true);
MethodHandle h=MethodHandles.lookup().unreflectConstructor(c);
Thread.State state=(Thread.State)h.invokeExact("FLYING", 42);
System.out.println("created Thread.State "+state+"("+state.ordinal()+')');
System.out.println(EnumSet.allOf(Thread.State.class).contains(state));
}
}
But don’t expect this solution to persist…
I try to set the --ignore-gpu-blacklist argument to JCEF but I can't find a way. The method I should be using is this one: CefApp::onBeforeCommandLineProcessing(String, CefCommandLine). But I can't find an example or good instructions of how to do it. CefCommandLine is an interface and I cannot find any implementation.
All the instructions I found are related to CEF, not JCEF and apparently there are classes that are different. Can anyone post a small example of how to pass Chromium arguments to CEF from a String str = "--ignore-gpu-blacklist"; ?
You have several possibilities to pass over arguments from JCEF to CEF/chromium.
1) The easiest way:
public static void main(String [] args) {
[...]
ArrayList<String> mySwitches = new ArrayList<>();
mySwitches.add("--persist-session-cookies=true");
CefApp app = CefApp.getInstance(mySwitches.toArray(new String[mySwitches.size()]));
CefClient client = app.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
[...]
}
Just create a string array, containing all your switches you want to pass over and assign that array to CefApp.getInstance(..) at the very first call of that static method.
If you have only some simple settings, you can use the class CefSettings as well and pass over the object to getInstance(). Beside that, you can combine both (there are four different "getInstance()" methods).
2) Create your own CefAppHandler implementation to do some advanced stuff.
(a) Create an own AppHandler:
public class MyAppHandler extends CefAppHandlerAdapter {
public MyAppHandler(String [] args) {
super(args);
}
#Override
public void onBeforeCommandLineProcessing(String process_type, CefCommandLine command_line) {
super.onBeforeCommandLineProcessing(process_type, command_line);
if (process_type.isEmpty()) {
command_line.appendSwitchWithValue("persist-session-cookies","true");
}
}
}
(b) Pass AppHandler over to CefApp
public static void main(String [] args) {
[...]
MyAppHandler appHandler = new MyAppHandler(args);
CefApp.addAppHandler(appHandler);
CefApp app = CefApp.getInstance(args);
CefClient client = app.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
[...]
}
Using this approach you'll do two things:
(a) you pass over the program arguments (args) to CefApp and
(b) you take the advantage of having the opportunity to manipulate the complete process of parsing the arguments within onBeforeCommandLineProcessing.
If you open the example code of JCEF detailed main frame, you will find this approach implemented in:
- tests.detailed.MainFrame.MainFrame(boolean, String, String[])
So implementing the onBeforeCommandLineProcessing is equal to CEF but written in Java instead of C/C++.
Regards,
Kai
Basically, I have a situation like this :
I want to know why the auto completion feature does't show the variable lineItems.
I am using Eclipse Kepler on Mac OS and pressing Control + Space.
EDIT :
I have looked at otter similar questions, and I believe I have the preferences set up correctly.
Because non-static variables can not be referenced from static context eclipse is much more smarter than we think just add static keyword to your list and it will show the suggestions.
Even if you write full name by your self still no use as it will give you error and from the configuration I think you will get suggestion for other functionalities.
Make an instance of TreeFormatter, or make the instance variable static.
import java.util.LinkedList;
import java.util.List;
public class TreeFormatter {
List<String> lineItems = new LinkedList<String>();
static List<String> staticlineItems = new LinkedList<String>();
public static void main(String[] args) {
// make an instance of TreeFormatter
TreeFormatter tf = new TreeFormatter();
tf.lineItems.add("foo");
// or make it static
staticlineItems.add("bar");
}
}
I'm not really sure how I can explain this, but here goes:
I want to be able to "insert" some commands into parts of my code which will be loaded from external files. To parse and execute these commands, I presumably have to use some scripting like BeanShell's eval method. The problem is that it doesn't seem to recognize the instance/method it's inside of. As a very basic example, I want to do something like
public void somethingHappens()
{
Foo foo = new Foo();
Interpreter i = new Interpreter();
i.eval("print(foo.getName());");
}
Is this possible? Should I use other scripting tools?
If you're using 1.6, you can use the built in JavaScript support.
The Java Scripting Programmer's Guide explains how to import Java classes into your script.
Code example 9 in this article explains how to pass objects into the script's scope.
Using beanshell, this is something you can try
package beanshell;
import bsh.EvalError;
import bsh.Interpreter;
public class DemoExample {
public static void main( String [] args ) throws EvalError {
Interpreter i = new bsh.Interpreter();
String usrIp = "if(\"abc\".equals(\"abc\")){"
+ "demoExmp.printValue(\"Rohit\");"
+ "}";
i.eval(""
+ "import beanshell.DemoExample;"
+ "DemoExample demoExmp = new beanshell.DemoExample();"
+ ""+usrIp);
}
public static void printValue(String strVal){
System.out.println("Printing Value "+strVal);
}
}