samedi 29 juillet 2023

Attempt to change static non final field throws IllegalArgument Exception

Class that has private static non final field

package sample;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {
   private static Logger logger = LoggerFactory.getLogger(App.class);

   public void doSomething() {
      logger.error("Cannot do something");
   }
}

Attempt to set this field through reflection

package sample;

import org.apache.logging.log4j.core.Logger;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;

import static org.mockito.Mockito.mock;

public class AppTest {

    @Test
    public void doSomething() throws Exception {
        App app = new App();

        Logger mockedLogger = mock(Logger.class);

        ReflectionTestUtils.setField(App.class, "logger", mockedLogger);
    }
}

results in IllegalArgumentException

Can not set static org.slf4j.Logger field sample.App.logger to org.apache.logging.log4j.core.Logger$MockitoMock$1185285221
java.lang.IllegalArgumentException: Can not set static org.slf4j.Logger field sample.App.logger to org.apache.logging.log4j.core.Logger$MockitoMock$1185285221
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeStaticObjectFieldAccessorImpl.set(UnsafeStaticObjectFieldAccessorImpl.java:79)
    at java.lang.reflect.Field.set(Field.java:764)
    at org.springframework.util.ReflectionUtils.setField(ReflectionUtils.java:633)

According to JavaDocs of invoked method

https://docs.spring.io/spring-framework/docs/5.2.20.RELEASE/javadoc-api/

Set the static field with the given name on the provided targetClass to the supplied value.

setting static field is supported.





vendredi 28 juillet 2023

Reflective access to *** is forbidden when targeting API 33 and above

I need to access the bootClassPathUrlHandlers in the VMClassLoader class using reflection but I am getting this error: "Reflective access to bootClassPathUrlHandlers is forbidden when targeting API 33 and above".

If I ignore it and run the app anyway I get this runtime exception: java.lang.NoSuchFieldException: No field bootClassPathUrlHandlers in class Ljava/lang/VMClassLoader; (declaration of 'java.lang.VMClassLoader' appears in /apex/com.android.art/javalib/core-libart.jar)

This is the part of code that I am using:

            Class cVMClassLoader = Class.forName("java.lang.VMClassLoader");
            Field vHandlers = cVMClassLoader.getDeclaredField("bootClassPathUrlHandlers");
            vHandlers.setAccessible(true);

            Object[] handlers = (Object[]) vHandlers.get(null);

How can I access it?





Find Java annotations via reflection for Kotlin getter

We have a wrapper class for checking the Android SDK version, and it uses the ChecksSdkIntAtLeast annotation. Here's a trimmed example of the class with just one getter and the logging removed:

class DeviceApi(
    private val deviceOsVersion: Int
) {
    @get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.M)
    val isApi23AndAbove get() = deviceOsVersion >= Build.VERSION_CODES.M
}

We have tests for the getter itself, but I was hoping to write tests to verify that the getter also has the annotation in place with the correct value, to avoid the compiler warnings that show up if it isn't included. However, no matter what I try, I can't seem to find the annotation via reflection.

Here's two basic examples that work if I do this for a Kotlin annotation class annotation that just don't find the public @interface annotations provided by androidx.annotation:

@Test
fun kotlin_reflection_example() {
    assertThat(DeviceApi::isApi23AndAbove.getter.hasAnnotation<ChecksSdkIntAtLeast>()).isTrue
}

@Test
fun java_reflection_example() {
    assertThat(DeviceApi::isApi23AndAbove.javaGetter!!.getAnnotation(ChecksSdkIntAtLeast::class.java)).isNotNull
}

I've also tried various examples I've seen online for looking for members and methods from the class and debugged to inspect the state of various things, but I've been unable to get any of the code to see the annotation. I want to know if I'm missing something obvious or if I found a scenario that just isn't supported by kotlin-reflect - and if so, if there's an alternative.





jeudi 27 juillet 2023

weird Json deserialization on a read-only property in C#

Can somebody explain how does it work? I even use reflection to set value to B, but it said B dont have a set value. How Newtonsoft.Json make this work?

public class A
{
    private int a = 10;
    public int B => a;
}

var a = new A();
var json = JsonConvert.SerializeObject(a);//json={"B":10}

//my expectation: this will have error, because B only have getter, dont have setter
//in reality: this run OK, and aa.B = aa.a = 10
var aa = JsonConvert.DeserializeObject<A>(json);




mercredi 26 juillet 2023

How could I run the constructor of all the classes in a package without knowing the names of all of the classes?

I want to make a class that would run the constructor of each class in the package, excluding itself of course. So I would be able to add another class to the package and the constructor of the class would be run without having to go and explicitly call it in the main class. Its for a minecraft plugin so its being compiled into a jar and run that way chat gpt said that made some kind of difference.

I've tried to get the package name and use that to get a path which would look for all of the files using a class loader. I'm able to get a list of the classes in a different project but not in the plugin.

public static List<Class<?>> getClassList() {
        List<Class<?>> classList = new ArrayList<>();
        String packageName=Loader.class.getPackage().getName();
        String packagePath = packageName.replace('.', '/');

        try {
            java.lang.ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            if (classLoader == null) {
                throw new ClassNotFoundException("Unable to get class loader.");
            }

            // Get all resources (files and directories) in the package directory
            java.util.Enumeration<java.net.URL> resources = classLoader.getResources(packagePath);
            while (resources.hasMoreElements()) {
                java.net.URL resource = resources.nextElement();
                if (resource.getProtocol().equals("file")) {
                    // If the resource is a file, get class objects
                    getClassObjectsFromFile(packageName, resource.getPath(), classList);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return classList;
    }

    private static void getClassObjectsFromFile(String packageName, String filePath, List<Class<?>> classList)
            throws ClassNotFoundException {
        java.io.File directory = new java.io.File(filePath);
        if (directory.exists()) {
            java.io.File[] files = directory.listFiles();
            if (files != null) {
                for (java.io.File file : files) {
                    if (file.isFile() && file.getName().endsWith(".class")) {
                        String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                        Class<?> clazz = Class.forName(className);
                        classList.add(clazz);
                    }
                }
            }
        }
    }

Thanks





mardi 25 juillet 2023

Get Parameters Pass into an method from an attribute

I have an attribute that I'm placing on a method:

[MyAttribute]
public void MyMethod(SomeClass prop) {
    //...
}

Lets say I'm invoking the method like so:

MyMethod(new SomeClass() { MyProp = 354});

I would like My attribute to be able to read in the properties which are passed into the method.

How can I Obtain access to the parameters of the method which the attribute is on. I would Imagine the call would look something like so:

var callStack = GetCallStack().
callStack.Pop();
var methodFrame = callStack.Current;
methodFrame.GetParameterAtIndex<SomeClass>(0);

Is there a way I can do this from the internals of the attribute?





lundi 24 juillet 2023

Is there an implicit type casting when using Functional Interfaces in Java?

I wrote the following Java code and expected it to not compile but it did and also executed counterintuitively. I am using Java 17.

TestFunctionExecutor.java

@FunctionalInterface
public interface TestFunctionExecutor{
    void execute();
}

TestClass.java

public class TestClass{
    public static void main(String... args) {
        TestClass test = new TestClass();
        test.wrapper(test::sampleFunction);
    }
    
    public void sampleFunction() {
        System.out.println("Inside sampleFunction");
    }

    public void wrapper(TestFunctionExecutor method) {
        System.out.println("Before method execution");
        method.execute();
        System.out.println("After method execution");
    }
}

Output -

Before method execution
Inside sampleFunction
After method execution

I thought since wrapper expects an argument of type TestFunctionExecutor and I am passing one of type TestClass the compilation should fail. I used a debugger and looks like method is a TestClass$$Lambda$1... at runtime. This confuses me and I have a few questions -

  1. What is the type of test::SampleFunction? Is it not TestClass or something like TestClass$$sampleFunction...? I am unable to deduce this with a debugger.
  2. Why were there no errors here? Looks like the types somehow became compatible, how?
  3. How does execute know what code to execute?
  4. Is this good code? My aim is to wrap a function so that some code runs before and after it.

Thanks!