Giter Site home page Giter Site logo

jooq / joor Goto Github PK

View Code? Open in Web Editor NEW
2.8K 116.0 377.0 512 KB

jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK's reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better.

Home Page: http://www.jooq.org/products

License: Apache License 2.0

Java 100.00%

joor's Introduction

Overview

jOOR stands for jOOR Object Oriented Reflection. It is a simple wrapper for the java.lang.reflect package.

jOOR's name is inspired by jOOQ, a fluent API for SQL building and execution.

Dependencies

None!

Download

For use with Java 9+

<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>joor</artifactId>
  <version>0.9.15</version>
</dependency>

For use with Java 8+

<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>joor-java-8</artifactId>
  <version>0.9.15</version>
</dependency>

For use with Java 6+

<dependency>
  <groupId>org.jooq</groupId>
  <artifactId>joor-java-6</artifactId>
  <version>0.9.15</version>
</dependency>

Simple example

// All examples assume the following static import:
import static org.joor.Reflect.*;

String world = onClass("java.lang.String") // Like Class.forName()
                .create("Hello World")     // Call most specific matching constructor
                .call("substring", 6)      // Call most specific matching substring() method
                .call("toString")          // Call toString()
                .get();                    // Get the wrapped object, in this case a String

Proxy abstraction

jOOR also gives access to the java.lang.reflect.Proxy API in a simple way:

public interface StringProxy {
  String substring(int beginIndex);
}

String substring = onClass("java.lang.String")
                    .create("Hello World")
                    .as(StringProxy.class) // Create a proxy for the wrapped object
                    .substring(6);         // Call a proxy method

Runtime compilation of Java code

jOOR has an optional dependency on the java.compiler module and simplifies access to javax.tools.JavaCompiler through the following API:

Supplier<String> supplier = Reflect.compile(
    "com.example.HelloWorld",
    "package com.example;\n" +
    "class HelloWorld implements java.util.function.Supplier<String> {\n" +
    "    public String get() {\n" +
    "        return \"Hello World!\";\n" +
    "    }\n" +
    "}\n").create().get();

// Prints "Hello World!"
System.out.println(supplier.get());

Comparison with standard java.lang.reflect

jOOR code:

Employee[] employees = on(department).call("getEmployees").get();

for (Employee employee : employees) {
  Street street = on(employee).call("getAddress").call("getStreet").get();
  System.out.println(street);
}

The same example with normal reflection in Java:

try {
  Method m1 = department.getClass().getMethod("getEmployees");
  Employee[] employees = (Employee[]) m1.invoke(department);

  for (Employee employee : employees) {
    Method m2 = employee.getClass().getMethod("getAddress");
    Address address = (Address) m2.invoke(employee);

    Method m3 = address.getClass().getMethod("getStreet");
    Street street = (Street) m3.invoke(address);

    System.out.println(street);
  }
}

// There are many checked exceptions that you are likely to ignore anyway 
catch (Exception ignore) {

  // ... or maybe just wrap in your preferred runtime exception:
  throw new RuntimeException(e);
}

Similar projects

Everyday Java reflection with a fluent interface:

Reflection modelled as XPath (quite interesting!)

joor's People

Contributors

alexengrig avatar amitjoy avatar cigaly avatar davsclaus avatar devdengchao avatar devinrsmith avatar igz-gp avatar iirekm avatar jakubgorski avatar knutwannheden avatar lukaseder avatar ooxi avatar simonracz avatar thomasdarimont avatar trentjeff avatar vbauer avatar verhas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

joor's Issues

Mention class name in documentation

Reflect.on is statically imported in all examples, but there is no mention from where. I had to look into the source to figure out which class to import.

Error of code with JSON

Expected behavior and actual behavior:

  1. To run the code from a json and compile it.
Exception in thread "main" org.joor.ReflectException: Compilation error: /io/github/xavierdd1st/TimeViewer.java:1: error: class, interface, or enum expected
nullpackage io.github.xavierdd1st.commands;import java.time.Clock;import java.time.ZoneId;public class TimeViewer extends Command {public void command() {Clock clock = Clock.system(ZoneId.systemDefault());CommandParser.setOutput( clock.toString() );}}
^
1 error

	at org.joor.Compile.compile(Compile.java:65)
	at org.joor.Reflect.compile(Reflect.java:77)
	at io.github.xavierdd1st.commands.CommandParser.parseCode(CommandParser.java:22)
	at io.github.xavierdd1st.commands.CommandHandler.setup(CommandHandler.java:16)
	at io.github.xavierdd1st.Main.<init>(Main.java:21)
	at io.github.xavierdd1st.Main.main(Main.java:35)

Steps to reproduce the problem:

Run the project.
https://github.com/XavierDD1st/TBUA

Versions:

  • jOOR: 0.9.9
  • Java: 8

create() won't find similar non-public constructors

            Constructor<?> constructor = type().getDeclaredConstructor(types);
            return on(constructor, args);
        }

        // If there is no exact match, try to find one that has a "similar"
        // signature if primitive argument types are converted to their wrappers
        catch (NoSuchMethodException e) {
            for (Constructor<?> constructor : type().getConstructors()) {

(should be getDeclaredConstructors)

[discussion] Merging capabilities with other projects to get something new

Hi guys,

I like JOOQ and seing reflections done in similar way is nice. But we have multiple projects in the wild, why don't agree and create a new fully featured reflection advanced API for all?

https://github.com/ronmamo/reflections
and most promising - https://github.com/EsotericSoftware/reflectasm
https://github.com/Genymobile/mirror

maybe there are others. This idea came to my head after reading tweet by Adam Bien (java champion):
https://twitter.com/AdamBien/status/966279325178875904

To create a testing framework for java applications fully based on reflections. But this is quite big amount of work and requires as well unified reflection API. What do you think guys, is there a space for merging powers to build something which can be used or integrated into testing frameworks later?

I refer here creators of other frameworks to put their oppinions on this idea. I welcome any kind of response.

@EsotericSoftware - reflect asm
@ronmamo
@CaptainBern - behind unmaintained project https://github.com/CaptainBern/Reflection
@Genymobile
@AdamBien - autor behind the tweet with original idea

I think unification of thee reflection advanced API could be fist initiative behind greater idea to auto test any application.

Call setAccessible(true) only if really needed

As reported by @hrj in jOOQ/jOOQ#3392


I have some code that sets up a SecurityManager with stringent permissions.

jOOQ fails while accessing a database because it calls setAccessible on private fields. I wonder why this is required.

Is reflection of private fields really required? Secondly, which code is being reflected? If it's code that has been generated by jOOQ, does it really need reflection?

I can temporarily work around this by granting suppressAccessChecks to jOOQ. But this is considered very bad practice. See this note. Quoting:

According to the technical note Permissions in the Java SE 6 Development Kit [Permissions 2008], Section ReflectPermission, target suppressAccessChecks:
Warning: Extreme caution should be taken before granting this permission to code, for it provides the ability to access fields and invoke methods in a class. This includes not only public, but protected and private fields and methods as well.

Can't pass "null" as a parameter to method call

Say I have a class,

public class MyPojo {
    private Map<String, String> parameters= new HashMap<>();

    public void addParameter(String name, String value)  {
        parameters.put(name, value);
    }
}

then,

MyPojo pojo = on(MyPojo.class).create().call("addParameter", paramName, null).get();

I get an NPE, Reflect.java (Line 550),

for (int i = 0; i < values.length; i++) {
    result[i] = values[i].getClass();
} 

Would it be possible to wildcard match the parameter when null is used?

Rethrow method internal exceptions

Expected behavior and actual behavior:

When calling a constructor or method, which is throwing an Exception, I'd expect that exception to be thrown as is - that's at least what I expect from a fluent API.

Steps to reproduce the problem:

// Currently throws a ReflectionException
// though (at least) I would expect it to throw a NullPointerException
Reflect.on(Example.class).create();

static class Example {
	Example() {
		throw new NullPointerException("Just an example!");
	}
}

Suggested change

Handling the InvocationTargetException and rethrowing its cause at below positions should handle things as described.

} catch (InvocationTargetException e) {
			throw (RuntimeException) e.getCause();

Versions:

  • jOOR: 0.9.9
  • Java: Oracle JDK 10.0.1

Cannot set final fields in JDK 9

In JDK 9 by default (i.e. when not opening the JDK modules to our modules), we cannot set final fields. This is why tests are failing on Travis, e.g.
https://travis-ci.org/jOOQ/jOOR/builds/357429643

[ERROR] testFinalFields(org.joor.test.ReflectTest)  Time elapsed: 0.005 s  <<< ERROR!
org.joor.ReflectException: java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.lang.reflect.Field.modifiers accessible: module java.base does not "opens java.lang.reflect" to module org.jooq.joor
	at org.jooq.joor/org.joor.test.ReflectTest.testFinalFields(ReflectTest.java:288)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.lang.reflect.Field.modifiers accessible: module java.base does not "opens java.lang.reflect" to module org.jooq.joor
	at org.jooq.joor/org.joor.test.ReflectTest.testFinalFields(ReflectTest.java:288)

We're going to leave the logic as it is, but ignore test failures on JDK 9 for the time being.

New Problems a Rise

Expected behavior and actual behavior:

To run.

file: C:\Project\TBUA\plugins\null.json
{"provider":"HappyPlugin","name":"TimeViewer","commandName":"time","info":"Shows the time","code":["package io.github.xavierdd1st.commands;","import java.time.Clock;","import java.time.ZoneId;","public class TimeViewer extends Command {","public void command() {","Clock clock \u003d Clock.system(ZoneId.systemDefault());","CommandParser.setOutput( clock.toString() );","}","}"]}
Exception in thread "main" org.joor.ReflectException: java.lang.reflect.InvocationTargetException
	at org.joor.Reflect.on(Reflect.java:781)
	at org.joor.Reflect.call(Reflect.java:463)
	at org.joor.Compile.compile(Compile.java:73)
	at org.joor.Reflect.compile(Reflect.java:77)
	at io.github.xavierdd1st.commands.CommandParser.parseCode(CommandParser.java:22)
	at io.github.xavierdd1st.commands.CommandHandler.setup(CommandHandler.java:16)
	at io.github.xavierdd1st.Main.<init>(Main.java:21)
	at io.github.xavierdd1st.Main.main(Main.java:35)
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.joor.Reflect.on(Reflect.java:777)
	... 7 more
Caused by: java.lang.NoClassDefFoundError: io/github/xavierdd1st/TimeViewer (wrong name: io/github/xavierdd1st/commands/TimeViewer)
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
	... 12 more

Steps to reproduce the problem:

Same steps
https://github.com/XavierDD1st/TBUA

Versions:

  • jOOR: 0.9.9
  • Java: 8

Add reflection cache

It would be slow if calling the same reflection methods from time to time, can the library provide this function?

Like https://github.com/Qihoo360/DroidPlugin/tree/master/project/Libraries/DroidPlugin/src/com/morgoo/droidplugin/reflect
FieldUtils.java:

public class FieldUtils {

    private static Map<String, Field> sFieldCache = new HashMap<String, Field>();
    ...
    private static Field getField(Class<?> cls, String fieldName, final boolean forceAccess) {
        Validate.isTrue(cls != null, "The class must not be null");
        Validate.isTrue(!TextUtils.isEmpty(fieldName), "The field name must not be blank/empty");

        String key = getKey(cls, fieldName);
        Field cachedField;
        synchronized (sFieldCache) {
            cachedField = sFieldCache.get(key);
        }
        if (cachedField != null) {
            if (forceAccess && !cachedField.isAccessible()) {
                cachedField.setAccessible(true);
            }
            return cachedField;
        }
        ...
    }
    ...
}

OSGi Support

I think people will be benefitted from this library if it can have OSGi Support so that people can use it in such dynamic execution environment.

Fail to set private static final variable

Hello,

First of all, thank you for the library, it's really useful :)

I found an issue when I want to reflect on a private final static variable (the worst case ^^), Joor throws a:
org.joor.ReflectException: java.lang.IllegalAccessException: Can not set static final boolean field com.ogoutay.robomocki3.BuildConfig.DEBUG to java.lang.Boolean

If I use my own Kotlin extension on top of your library, it works well:

Reflect.setFinalStatic(name: String, newValue: Any) {
    val field = this.get<Class<*>>().getDeclaredField(name)

    field.isAccessible = true
    val modifiersField = Field::class.java.getDeclaredField("modifiers")
    modifiersField.isAccessible = true
    modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv())

    field.set(null, newValue)
}

Do you know where the problem could come from?

Thank you in advance

Cheers,

Olivier

Incorrect groupId in pom.xml?

Lukas, this might be the most underrated library of all time, kudos.

The POM file lists the groupId as org.jooq, even though the package namespace for the code is org.joor. Perhaps this was intentional so you could manage all the JOO* projects you're working on with the same coordinates in the central repo.

Either way it stumped me when I accidentally added org.joor and Maven couldn't find the dependency. I thought I'd raise an issue just it case it was an actual typo, if not, disregard and close. Thanks.

Reflect.get(name) fails for public Fields of private nested classes

The unit test

    private static class PrivateConstructors {

        public final String string;

        private PrivateConstructors() {
            this("defaultConstructor");
        }

        private PrivateConstructors(String string) {
            this.string = string;
        }
    }

    @Test
    public void createsReflectInstanceCallingPrivateDefaultConstructor() {
        assertEquals(on(PrivateConstructors.class).create().get("string"), "defaultConstructor");

    }

fails with the error:

org.joor.ReflectException: java.lang.IllegalAccessException: Class org.joor.Reflect can not access a member of class org.joor.test.ReflectTest$PrivateConstructors with modifiers "public final"

The fix is to modify the method field0 to

   private Field field0(String name) throws ReflectException {
        Class<?> type = type();

        // Try getting a public field
        try {
            return accessible(type.getField(name));
        }
...

to set the returned field accessible in case it is not.

Choose the most specific method when calling overloaded methods

Currently, jOOR chooses the "first" matching method if multiple overloaded methods are applicable. E.g.:

void method(Object o);
void method(Number o);
void method(Integer o);

// This should call method(Number), but it may also call method(Object)
on(Test.class).create(new Long("1"));

Finding the most specific method according to the rules of the JLS is not easy, in particular because jOOR follows its own rules. E.g., in the future, we may also want to consider private methods to be eligible for the search algorithm.

Runtime compilation fails when executing within a fat jar (e.g. jar produced by spring boot)

Expected behavior and actual behavior:

Expected behavior: runtime class compiles.
Actual behavior: compilation fails if compiled code references a class that is in a jar within a fat jar.

Steps to reproduce the problem:

Create a class called Foo.java. Create a jar with this. Create a class called Bar.java that compiles a class that derives from Foo. Create a super-jar with Bar.java and the jar containing Foo.java.
Run bar.java using Spring boot created super-jar (fat jar).

Versions:

  • jOOR: 0.9.9
  • Java: 8

The core issue is that the classpath entry created by spring-boot class loader looks like this:
//super-jar.jar!/lib/foo.jar

It doesn't look like the Tool compiler can handle such a classpath reference (alas, there even seems to be a request going back to 2002 asking to add support for such a thing).

Support setting values on final fields

When using jOOR to access private static classes or private final fields I get an access exception. Therefore I have two questions

  1. Why doesn't jOOR automatically try to modify the accessibility?
  2. How to modify the accessibility manually? I know of the method Reflect.accessible but I don't know how to get field references without using java.lang.reflect

Reflection on MethodHandles$Lookup fails in JDK 9

In JDK 9.0.1, tests fail as can be seen on travis:
https://travis-ci.org/jOOQ/jOOR/builds/357395818

Curiously, it doesn't fail in JDK 10.0.0, nor in 9.0.4. Perhaps some regression in the JDK...

java.lang.ExceptionInInitializerError
	at org.jooq.joor/org.joor.test.ReflectTest.testType(ReflectTest.java:473)
Caused by: java.lang.IllegalStateException: java.lang.reflect.InaccessibleObjectException: Unable to make java.lang.invoke.MethodHandles$Lookup(java.lang.Class) accessible: module java.base does not "opens java.lang.invoke" to module org.jooq.joor
	at org.jooq.joor/org.joor.test.ReflectTest.testType(ReflectTest.java:473)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make java.lang.invoke.MethodHandles$Lookup(java.lang.Class) accessible: module java.base does not "opens java.lang.invoke" to module org.jooq.joor
	at org.jooq.joor/org.joor.test.ReflectTest.testType(ReflectTest.java:473)

We should use JDK 9's new API MethodHandles.privateLookupIn()

java.lang.NoSuchFieldException: modifiers on Reflect.set() on Android

Expected behavior and actual behavior:

Reflect.on(httpUrl).set("a", "http");

Steps to reproduce the problem:

org.joor.ReflectException: java.lang.NoSuchFieldException: modifiers

Versions:

  • system : android 4.x
  • jOOR: 0.9.7
  • Java: 6

====

I found the problem in the code :

    public Reflect set(String name, Object value) throws ReflectException {
        try {
            Field field = field0(name);
            if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
                Field modifiersField = Field.class.getDeclaredField("modifiers");//android system don't have this field.
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            }
            field.set(object, unwrap(value));
            return this;
        }
        catch (Exception e) {
            throw new ReflectException(e);
        }
    }

Illegal reflective access when running jOOR-java-8 on Java 10

jOOR-java-8's static initialiser runs a reflective access:

    static {
        Constructor<MethodHandles.Lookup> result;

        /* [java-9] */
        if (true)
            result = null;
        else
        /* [/java-9] */
        try {
            // The following call is a problem:
            result = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);

            if (!result.isAccessible())
                result.setAccessible(true);
        }

        // Can no longer access the above in JDK 9
        catch (Throwable ignore) {
            result = null;
        }

        CACHED_LOOKUP_CONSTRUCTOR = result;
    }

As can be seen, the modularised Java 9 distribution doesn't run this check. Also, the Java 6 distribution doesn't run it. The entire initialiser is removed from the Java 6 distribution. While this check is OK to run on a JDK 8, people might use the Java 8 distribution also on Java 9. We should replace the compile-time preprocessing "check" by a runtime check:

    static final boolean                           JAVA_9;

    static {

        // Runtime detection if we're on Java 9
        boolean java9;

        try {
            Optional.class.getMethod("stream");
            java9 = true;
        }
        catch (NoSuchMethodException e) {
            java9 = false;
        }

        JAVA_9 = java9;

        Constructor<MethodHandles.Lookup> result = null;

        if (!java9) {
            try {
                result = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);

                if (!result.isAccessible())
                    result.setAccessible(true);
            }

            // Can no longer access the above in JDK 9
            catch (Throwable ignore) {
            }
        }

        CACHED_LOOKUP_CONSTRUCTOR = result;
    }

This issue is also present in jOOQ, where the shaded jOOR dependency doesn't have a Java 9 version yet:
jOOQ/jOOQ#7594

Subclassing using lambdas

As originally reported by @C4Phone here: jOOQ/jOOL#331


Hi, I just found out this library and jOOR. I really like your projects. I'd like it better if you guys could achieve "subclassing" interfaces and/or abstract classes using lambdas. This would be very helpful for using Java as an interpreted language.

Expected behavior and actual behavior:

I don't know whether similar functionalities exist. But this is what I expect:

// Run this code in a jupyter notebook.
interface Counter {
  // This is an interface, but it can also be an abstract class
  void add();
  void show();
}

org.joor.Reflect myClass = lambdaSubclass(on(Counter))
  .addField("counter", Integer.class)
  .setDefaultConstructor(self -> self.set("counter", 0))
  .set("add",  self -> self.set("counter", self.get("counter") +1)),
       "show", self -> System.out.println(self.get("counter")))  // "set" is a function of variable length.
  .doneSubclass();

Counter x = myClass.create();
x.add();
x.show();
x.add();
x.show();

// Should print 1 then print 2.

Is this possible or already implemented? If not, can I request this functionality and/or help implement it? Thank you!

java.lang.ClassCastException

Expected behavior and actual behavior:

To run.

{"provider":"HappyPlugin","name":"TimeViewer","commandName":"time","info":"Shows the time","code":["package io.github.xavierdd1st.commands;","import java.time.Clock;","import java.time.ZoneId;","public class TimeViewer extends Command {","public void command() {","Clock clock \u003d Clock.system(ZoneId.systemDefault());","CommandParser.setOutput( clock.toString() );","}","}"]}
Exception in thread "main" java.lang.ClassCastException: io.github.xavierdd1st.commands.TimeViewer cannot be cast to java.util.function.Supplier
	at io.github.xavierdd1st.commands.CommandParser.parseCode(CommandParser.java:23)
	at io.github.xavierdd1st.commands.CommandHandler.setup(CommandHandler.java:16)
	at io.github.xavierdd1st.Main.<init>(Main.java:21)
	at io.github.xavierdd1st.Main.main(Main.java:35)```
### Steps to reproduce the problem:
Run code;
https://github.com/XavierDD1st/TBUA
### Versions:

- jOOR: 0.9.9
- Java: 8

Add Reflect.initValue(Class)

Sometimes, it's necessary to get an initialisation value for a given Class reference, i.e. the value that would be present as a default initialisation value after object construction:

class X {
  i int;
}

assertEquals(0, new X().i);

There doesn't seem to be a JDK method to do this. Guava has a method, though:
https://stackoverflow.com/q/52988458/521799

Add license file to the repository

I would recommend adding a LICENSE file (or note to README) to this repository. I found on your (old?) Google Code pages that you're releasing under Apache, but I think it should be here on GitHub too.

Add Reflect.compile(String, String) to create a runtime-compiled class

A new method Reflect.compile(String className, String content) should allow for accessing the java.compile module, and specifically the JavaCompiler API in a transparent way. Usage example:

package org.joor.test;

import static junit.framework.Assert.*;

import org.joor.Reflect;
import org.joor.test.CompileTest.J;
import org.junit.Test;

/**
 * @author Lukas Eder
 */
public class CompileTest {

    @Test
    public void testCompile() throws Exception {
        I i = Reflect.compile("org.joor.test.Test1", "package org.joor.test; public class Test1 implements org.joor.test.I {}").create().get();
        assertEquals("I.m()", i.m());

        J j = Reflect.compile("org.joor.test.Test2", "package org.joor.test; public class Test2 implements org.joor.test.CompileTest.J {}").create().get();
        assertEquals("J.m()", j.m());
    }


    interface J {
        default String m() {
            return "J.m()";
        }
    }
}

interface I extends J {
    @Override
    default String m() {
        return "I.m()";
    }
}

Reflect on(Class<?> type, Object object) become public?

Expected behavior and actual behavior:

when i want to use joor on a String object to read its field.
i found a question.

when i write on("abc"), 2 method match.

  1. on(String)
  2. on(Object o);

the second is which i want to use.

Steps to reproduce the problem:

      String abc = "abc";
         Object o = abc;  
        Map<java.lang.String, Reflect> fields = on(o).fields();
        System.out.println("fields = " + fields);

if i don't use Object to hold string, always call the on(String) overload due to single dispatch.

Versions:

  • jOOR 0.9.7
  • Java: 8

Fail to set private static final variable in Android

In Android, jOOR doesn't work when reflect final field by jOOR.

Because Field class in Android is different from the same file in JDK, as follows, there is no accessFlags field in this class:

/*
 * Copyright (C) 2014 The Android Open Source Project
 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package java.lang.reflect;

import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import java.lang.annotation.Annotation;
import java.util.Map;
import com.android.dex.Dex;
import libcore.reflect.GenericSignatureParser;
import java.util.List;


/**
 * A {@code Field} provides information about, and dynamic access to, a
 * single field of a class or an interface.  The reflected field may
 * be a class (static) field or an instance field.
 *
 * <p>A {@code Field} permits widening conversions to occur during a get or
 * set access operation, but throws an {@code IllegalArgumentException} if a
 * narrowing conversion would occur.
 *
 * @see Member
 * @see java.lang.Class
 * @see java.lang.Class#getFields()
 * @see java.lang.Class#getField(String)
 * @see java.lang.Class#getDeclaredFields()
 * @see java.lang.Class#getDeclaredField(String)
 *
 * @author Kenneth Russell
 * @author Nakul Saraiya
 */
public final
class Field extends AccessibleObject implements Member {

    private int accessFlags;
    private Class<?> declaringClass;
    private int dexFieldIndex;
    private int offset;
    private Class<?> type;

    private Field() {
    }

    /**
     * Returns the {@code Class} object representing the class or interface
     * that declares the field represented by this {@code Field} object.
     */
    public Class<?> getDeclaringClass() {
        return declaringClass;
    }

    /**
     * Returns the name of the field represented by this {@code Field} object.
     */
    public String getName() {
        if (dexFieldIndex == -1) {
            // Proxy classes have 1 synthesized static field with no valid dex index.
            if (!declaringClass.isProxy()) {
                throw new AssertionError();
            }
            return "throws";
        }
        Dex dex = declaringClass.getDex();
        int nameIndex = dex.nameIndexFromFieldIndex(dexFieldIndex);
        return declaringClass.getDexCacheString(dex, nameIndex);
    }

    /**
     * Returns the Java language modifiers for the field represented
     * by this {@code Field} object, as an integer. The {@code Modifier} class should
     * be used to decode the modifiers.
     *
     * @see Modifier
     */
    public int getModifiers() {
        return accessFlags & 0xffff;  // mask out bits not used by Java
    }

    /**
     * Returns {@code true} if this field represents an element of
     * an enumerated type; returns {@code false} otherwise.
     *
     * @return {@code true} if and only if this field represents an element of
     * an enumerated type.
     * @since 1.5
     */
    public boolean isEnumConstant() {
        return (getModifiers() & Modifier.ENUM) != 0;
    }

    /**
     * Returns {@code true} if this field is a synthetic
     * field; returns {@code false} otherwise.
     *
     * @return true if and only if this field is a synthetic
     * field as defined by the Java Language Specification.
     * @since 1.5
     */
    public boolean isSynthetic() {
        return Modifier.isSynthetic(getModifiers());
    }

    /**
     * Returns a {@code Class} object that identifies the
     * declared type for the field represented by this
     * {@code Field} object.
     *
     * @return a {@code Class} object identifying the declared
     * type of the field represented by this object
     */
    public Class<?> getType() {
        return type;
    }

    /**
     * Returns a {@code Type} object that represents the declared type for
     * the field represented by this {@code Field} object.
     *
     * <p>If the {@code Type} is a parameterized type, the
     * {@code Type} object returned must accurately reflect the
     * actual type parameters used in the source code.
     *
     * <p>If the type of the underlying field is a type variable or a
     * parameterized type, it is created. Otherwise, it is resolved.
     *
     * @return a {@code Type} object that represents the declared type for
     *     the field represented by this {@code Field} object
     * @throws GenericSignatureFormatError if the generic field
     *     signature does not conform to the format specified in
     *     <cite>The Java&trade; Virtual Machine Specification</cite>
     * @throws TypeNotPresentException if the generic type
     *     signature of the underlying field refers to a non-existent
     *     type declaration
     * @throws MalformedParameterizedTypeException if the generic
     *     signature of the underlying field refers to a parameterized type
     *     that cannot be instantiated for any reason
     * @since 1.5
     */
    public Type getGenericType() {
        String signatureAttribute = getSignatureAttribute();
        ClassLoader cl = declaringClass.getClassLoader();
        GenericSignatureParser parser = new GenericSignatureParser(cl);
        parser.parseForField(declaringClass, signatureAttribute);
        Type genericType = parser.fieldType;
        if (genericType == null) {
            genericType = getType();
        }
        return genericType;
    }

    private String getSignatureAttribute() {
        String[] annotation = getSignatureAnnotation();
        if (annotation == null) {
            return null;
        }
        StringBuilder result = new StringBuilder();
        for (String s : annotation) {
            result.append(s);
        }
        return result.toString();
    }
    private native String[] getSignatureAnnotation();


    /**
     * Compares this {@code Field} against the specified object.  Returns
     * true if the objects are the same.  Two {@code Field} objects are the same if
     * they were declared by the same class and have the same name
     * and type.
     */
    public boolean equals(Object obj) {
        if (obj != null && obj instanceof Field) {
            Field other = (Field)obj;
            return (getDeclaringClass() == other.getDeclaringClass())
                && (getName() == other.getName())
                && (getType() == other.getType());
        }
        return false;
    }

    /**
     * Returns a hashcode for this {@code Field}.  This is computed as the
     * exclusive-or of the hashcodes for the underlying field's
     * declaring class name and its name.
     */
    public int hashCode() {
        return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
    }

    /**
     * Returns a string describing this {@code Field}.  The format is
     * the access modifiers for the field, if any, followed
     * by the field type, followed by a space, followed by
     * the fully-qualified name of the class declaring the field,
     * followed by a period, followed by the name of the field.
     * For example:
     * <pre>
     *    public static final int java.lang.Thread.MIN_PRIORITY
     *    private int java.io.FileDescriptor.fd
     * </pre>
     *
     * <p>The modifiers are placed in canonical order as specified by
     * "The Java Language Specification".  This is {@code public},
     * {@code protected} or {@code private} first, and then other
     * modifiers in the following order: {@code static}, {@code final},
     * {@code transient}, {@code volatile}.
     */
    public String toString() {
        int mod = getModifiers();
        return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
            + getTypeName(getType()) + " "
            + getTypeName(getDeclaringClass()) + "."
            + getName());
    }

    /**
     * Returns a string describing this {@code Field}, including
     * its generic type.  The format is the access modifiers for the
     * field, if any, followed by the generic field type, followed by
     * a space, followed by the fully-qualified name of the class
     * declaring the field, followed by a period, followed by the name
     * of the field.
     *
     * <p>The modifiers are placed in canonical order as specified by
     * "The Java Language Specification".  This is {@code public},
     * {@code protected} or {@code private} first, and then other
     * modifiers in the following order: {@code static}, {@code final},
     * {@code transient}, {@code volatile}.
     *
     * @return a string describing this {@code Field}, including
     * its generic type
     *
     * @since 1.5
     */
    public String toGenericString() {
        int mod = getModifiers();
        Type fieldType = getGenericType();
        return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
            +  ((fieldType instanceof Class) ?
                getTypeName((Class)fieldType): fieldType.toString())+ " "
            + getTypeName(getDeclaringClass()) + "."
            + getName());
    }

    /**
     * Returns the value of the field represented by this {@code Field}, on
     * the specified object. The value is automatically wrapped in an
     * object if it has a primitive type.
     *
     * <p>The underlying field's value is obtained as follows:
     *
     * <p>If the underlying field is a static field, the {@code obj} argument
     * is ignored; it may be null.
     *
     * <p>Otherwise, the underlying field is an instance field.  If the
     * specified {@code obj} argument is null, the method throws a
     * {@code NullPointerException}. If the specified object is not an
     * instance of the class or interface declaring the underlying
     * field, the method throws an {@code IllegalArgumentException}.
     *
     * <p>If this {@code Field} object is enforcing Java language access control, and
     * the underlying field is inaccessible, the method throws an
     * {@code IllegalAccessException}.
     * If the underlying field is static, the class that declared the
     * field is initialized if it has not already been initialized.
     *
     * <p>Otherwise, the value is retrieved from the underlying instance
     * or static field.  If the field has a primitive type, the value
     * is wrapped in an object before being returned, otherwise it is
     * returned as is.
     *
     * <p>If the field is hidden in the type of {@code obj},
     * the field's value is obtained according to the preceding rules.
     *
     * @param object object from which the represented field's value is
     * to be extracted
     * @return the value of the represented field in object
     * {@code obj}; primitive values are wrapped in an appropriate
     * object before being returned
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof).
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     */
    public native Object get(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance {@code boolean} field.
     *
     * @param object the object to extract the {@code boolean} value
     * from
     * @return the value of the {@code boolean} field
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code boolean} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#get
     */
    public native boolean getBoolean(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance {@code byte} field.
     *
     * @param object the object to extract the {@code byte} value
     * from
     * @return the value of the {@code byte} field
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code byte} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#get
     */
    public native byte getByte(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance field of type
     * {@code char} or of another primitive type convertible to
     * type {@code char} via a widening conversion.
     *
     * @param object the object to extract the {@code char} value
     * from
     * @return the value of the field converted to type {@code char}
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code char} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see Field#get
     */
    public native char getChar(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance field of type
     * {@code short} or of another primitive type convertible to
     * type {@code short} via a widening conversion.
     *
     * @param object the object to extract the {@code short} value
     * from
     * @return the value of the field converted to type {@code short}
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code short} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#get
     */
    public native short getShort(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance field of type
     * {@code int} or of another primitive type convertible to
     * type {@code int} via a widening conversion.
     *
     * @param object the object to extract the {@code int} value
     * from
     * @return the value of the field converted to type {@code int}
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code int} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#get
     */
    public native int getInt(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance field of type
     * {@code long} or of another primitive type convertible to
     * type {@code long} via a widening conversion.
     *
     * @param object the object to extract the {@code long} value
     * from
     * @return the value of the field converted to type {@code long}
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code long} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#get
     */
    public native long getLong(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance field of type
     * {@code float} or of another primitive type convertible to
     * type {@code float} via a widening conversion.
     *
     * @param object the object to extract the {@code float} value
     * from
     * @return the value of the field converted to type {@code float}
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code float} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see Field#get
     */
    public native float getFloat(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Gets the value of a static or instance field of type
     * {@code double} or of another primitive type convertible to
     * type {@code double} via a widening conversion.
     *
     * @param object the object to extract the {@code double} value
     * from
     * @return the value of the field converted to type {@code double}
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is inaccessible.
     * @exception IllegalArgumentException  if the specified object is not
     *              an instance of the class or interface declaring the
     *              underlying field (or a subclass or implementor
     *              thereof), or if the field value cannot be
     *              converted to the type {@code double} by a
     *              widening conversion.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#get
     */
    public native double getDouble(Object object)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the field represented by this {@code Field} object on the
     * specified object argument to the specified new value. The new
     * value is automatically unwrapped if the underlying field has a
     * primitive type.
     *
     * <p>The operation proceeds as follows:
     *
     * <p>If the underlying field is static, the {@code obj} argument is
     * ignored; it may be null.
     *
     * <p>Otherwise the underlying field is an instance field.  If the
     * specified object argument is null, the method throws a
     * {@code NullPointerException}.  If the specified object argument is not
     * an instance of the class or interface declaring the underlying
     * field, the method throws an {@code IllegalArgumentException}.
     *
     * <p>If this {@code Field} object is enforcing Java language access control, and
     * the underlying field is inaccessible, the method throws an
     * {@code IllegalAccessException}.
     *
     * <p>If the underlying field is final, the method throws an
     * {@code IllegalAccessException} unless {@code setAccessible(true)}
     * has succeeded for this {@code Field} object
     * and the field is non-static. Setting a final field in this way
     * is meaningful only during deserialization or reconstruction of
     * instances of classes with blank final fields, before they are
     * made available for access by other parts of a program. Use in
     * any other context may have unpredictable effects, including cases
     * in which other parts of a program continue to use the original
     * value of this field.
     *
     * <p>If the underlying field is of a primitive type, an unwrapping
     * conversion is attempted to convert the new value to a value of
     * a primitive type.  If this attempt fails, the method throws an
     * {@code IllegalArgumentException}.
     *
     * <p>If, after possible unwrapping, the new value cannot be
     * converted to the type of the underlying field by an identity or
     * widening conversion, the method throws an
     * {@code IllegalArgumentException}.
     *
     * <p>If the underlying field is static, the class that declared the
     * field is initialized if it has not already been initialized.
     *
     * <p>The field is set to the possibly unwrapped and widened new value.
     *
     * <p>If the field is hidden in the type of {@code obj},
     * the field's value is set according to the preceding rules.
     *
     * @param object the object whose field should be modified
     * @param value the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     */
    public native void set(Object object, Object value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code boolean} on the specified object.
     * This method is equivalent to
     * {@code set(obj, zObj)},
     * where {@code zObj} is a {@code Boolean} object and
     * {@code zObj.booleanValue() == z}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setBoolean(Object object, boolean value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code byte} on the specified object.
     * This method is equivalent to
     * {@code set(obj, bObj)},
     * where {@code bObj} is a {@code Byte} object and
     * {@code bObj.byteValue() == b}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setByte(Object object, byte value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code char} on the specified object.
     * This method is equivalent to
     * {@code set(obj, cObj)},
     * where {@code cObj} is a {@code Character} object and
     * {@code cObj.charValue() == c}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setChar(Object object, char value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code short} on the specified object.
     * This method is equivalent to
     * {@code set(obj, sObj)},
     * where {@code sObj} is a {@code Short} object and
     * {@code sObj.shortValue() == s}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setShort(Object object, short value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as an {@code int} on the specified object.
     * This method is equivalent to
     * {@code set(obj, iObj)},
     * where {@code iObj} is a {@code Integer} object and
     * {@code iObj.intValue() == i}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setInt(Object object, int value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code long} on the specified object.
     * This method is equivalent to
     * {@code set(obj, lObj)},
     * where {@code lObj} is a {@code Long} object and
     * {@code lObj.longValue() == l}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setLong(Object object, long value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code float} on the specified object.
     * This method is equivalent to
     * {@code set(obj, fObj)},
     * where {@code fObj} is a {@code Float} object and
     * {@code fObj.floatValue() == f}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setFloat(Object object, float value)
            throws IllegalAccessException, IllegalArgumentException;

    /**
     * Sets the value of a field as a {@code double} on the specified object.
     * This method is equivalent to
     * {@code set(obj, dObj)},
     * where {@code dObj} is a {@code Double} object and
     * {@code dObj.doubleValue() == d}.
     *
     * @param object the object whose field should be modified
     * @param value   the new value for the field of {@code obj}
     * being modified
     *
     * @exception IllegalAccessException    if this {@code Field} object
     *              is enforcing Java language access control and the underlying
     *              field is either inaccessible or final.
     * @exception IllegalArgumentException  if the specified object is not an
     *              instance of the class or interface declaring the underlying
     *              field (or a subclass or implementor thereof),
     *              or if an unwrapping conversion fails.
     * @exception NullPointerException      if the specified object is null
     *              and the field is an instance field.
     * @exception ExceptionInInitializerError if the initialization provoked
     *              by this method fails.
     * @see       Field#set
     */
    public native void setDouble(Object object, double value)
            throws IllegalAccessException, IllegalArgumentException;

    /*
     * Utility routine to paper over array type names
     */
    static String getTypeName(Class<?> type) {
        if (type.isArray()) {
            try {
                Class<?> cl = type;
                int dimensions = 0;
                while (cl.isArray()) {
                    dimensions++;
                    cl = cl.getComponentType();
                }
                StringBuffer sb = new StringBuffer();
                sb.append(cl.getName());
                for (int i = 0; i < dimensions; i++) {
                    sb.append("[]");
                }
                return sb.toString();
            } catch (Throwable e) { /*FALLTHRU*/ }
        }
        return type.getName();
    }

    /**
     * @throws NullPointerException {@inheritDoc}
     * @since 1.5
     */
    @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
        if (annotationType == null) {
            throw new NullPointerException("annotationType == null");
        }
        return getAnnotationNative(annotationType);
    }
    private native <A extends Annotation> A getAnnotationNative(Class<A> annotationType);

    @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
        if (annotationType == null) {
            throw new NullPointerException("annotationType == null");
        }
        return isAnnotationPresentNative(annotationType);
    }
    private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);

    /**
     * @since 1.5
     */
    @Override public native Annotation[] getDeclaredAnnotations();

    /**
     * Returns the index of this field's ID in its dex file.
     *
     * @hide
     */
    public int getDexFieldIndex() {
        return dexFieldIndex;
    }

    /**
     * Returns the offset of the field within an instance, or for static fields, the class.
     *
     * @hide
     */
    public int getOffset() {
        return offset;
    }
}

Dynamic compilation with provided ClassLoader

Hi, is it possible to create overloaded Compile.compile(String, String, ClassLoader) and Reflect.compile(String, String, ClassLoader)?

I use Apache CXF to create dynamic SOAP web service client, but it loads the classes on a new ClassLoader instance, so I can't reference them on my class compiled by Reflect.compile(String, String).

I may try submit a PR later.

Reflect#type on instance fails for null field

When using joor 0.9.6, this test:

public static class A {
    String f;
}

@Test
public void test() {
    A a = new A();
    for (Map.Entry<String, Reflect> field : Reflect.on(a).fields().entrySet()) {
        Reflect reflect = field.getValue();
        if (reflect.type() == String.class) {
            System.out.println("Value: " + reflect.get());
        }
    }
}

fails with:

java.lang.NullPointerException
	at org.joor.Reflect.type(Reflect.java:766)

By the way: Thank you very much for providing jOOR! ๐Ÿ‘

Fields and methods from superclasses are invisible

To finding non-public fields or methods you use code like

    private Method exactMethod(String name, Class<?>[] types) throws NoSuchMethodException {
        final Class<?> type = type();

        // first priority: find a public method with exact signature match in class hierarchy
        try {
            return type.getMethod(name, types);
        }

        // second priority: find a private method with exact signature match on declaring class
        catch (NoSuchMethodException e) {
            return type.getDeclaredMethod(name, types);
        }
    }

It's incorrect, it looks for fields/methods only in type(), doesn't work if the field/method is in some superclass.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.