vendredi 30 septembre 2022

How can I statically acquire the type of an inheriting class from an inherited method?

The problem:

Given I have the following:

using System;
public class BaseClass{
        public static Type TypeOfThis => //Somehow get the type of the inheriting class?
        public static void HelloWorld() => Console.WriteLine($"Hello world, I am {TypeOfThis.Name}");
}
public class InheritingClass:BaseClass{}

How can I reference the type of the inheriting class?

GetType requires a reference, which we do not have, as we are working statically.





How to iterate through the members of a standard module

My goal is to list the procedures exposed by the compiled VBProject, as visible in the Excel Macros menu or when typing a cell formula which makes appear availble UDF. A Solution that list any member (Enum, Sub, Function, etc.) of a CodeModule or of the full VBProject would be ideal.

I am not looking for a code parsing solution.

I could find old mentions of a way to do so in VB with the VBIDE library, which ( should / used to ) expose a VBIDE.Member class (accessible via the CodeModule.Members property) with those interesting properties:

Member.Name As String
Member.Type As VBIDE.vbext_MemberType
Member.Scope As VBIDE.vbext_Scope

For a reason I don't understand, I cannot access them via VBA and the VBIDE library, there are not even listed as hidden members.

Is there a way to get them? Rubberduck (previously known as Mat's Mug heon Stack Overflow) aka Mathieu Guindon suggests it is possible though: https://rubberduckvba.wordpress.com/2016/03/24/a-reflection-on-vba-reflection/

Another idea: how to use Reflection with VBA? Again, he suggests it is possible: https://rubberduckvba.wordpress.com/2019/04/10/whats-wrong-with-vba/

Note: the Rubberduck COM Add-In that integrates with the VBE, is able to do it (using .NET as I understand it)





Geeting error when reflecting .class file from jar file which .class file is extending or implementing other class which class is present in dependenc

I have a jar file which contains only testcase.class files. I need to parse that and find all the classes defined in that jar file and need to generate one report. I tried to do it with the reflection concept in Java. Some how, when loading a class is fine, but trying to get the declared methods of it, I am getting the following error. (Note class is loaded, I am able to get the name and canonical name of the loaded class but I error at trying to get declared methods).

for (String clazz: classes) {  
            String className = clazz.replaceAll("/",  
 ".").replaceAll(".class","");  
            try {  
                URL url = file.toURI().toURL();  
                URL[] urls = new URL[]{url};  
                URLClassLoader cl = new URLClassLoader(urls);  
                Class cls = cl.loadClass(className);  
                System.out.println("##############################");  
                cls.getDeclaredMethods();
                //clazzes.add(getClassObject(cls));  
                //break;  
            } catch (MalformedURLException e) {  
                e.printStackTrace();  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            }  
        }  



Exception in thread "main" java.lang.NoClassDefFoundError: javax/mail/Authenticator
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
    at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:555)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:452)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:451)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at com.springboot.example.springBootExample.service.JarParserService.getTypes(JarParserService.java:99)
    at com.springboot.example.springBootExample.service.JarParserService.constructPackages(JarParserService.java:86)
    at com.springboot.example.springBootExample.service.JarParserService.getClassTypes(JarParserService.java:78)
    at com.springboot.example.springBootExample.service.JarParserService.scanJar(JarParserService.java:61)
    at com.springboot.example.springBootExample.service.JarParserService.getAllPackages(JarParserService.java:34)
    at com.springboot.example.springBootExample.service.FindClassesFromJarService.parseJar(FindClassesFromJarService.java:61)
    at com.springboot.example.springBootExample.service.FindClassesFromJarService.main(FindClassesFromJarService.java:31)
Caused by: java.lang.ClassNotFoundException: javax.mail.Authenticator
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 17 more

Process finished with exit code 1




jeudi 29 septembre 2022

Allow reflection from non-owned library

I'm facing a future problem that I have to solve right now and the problem is a class from a library I do not own (Jackson) that is accessing through reflection to another. To be more specific, this is the warning that I'm trying to solve:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.fasterxml.jackson.module.afterburner.util.MyClassLoader (file:/Users/pedro.maria/.m2/repository/com/fasterxml/jackson/module/jackson-module-afterburner/2.13.4/jackson-module-afterburner-2.13.4.jar) to method java.lang.ClassLoader.findLoadedClass(java.lang.String)
WARNING: Please consider reporting this to the maintainers of com.fasterxml.jackson.module.afterburner.util.MyClassLoader
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Now, the most frustrating part is that I'm staring the solution in the face, the --add-opens flag that needs to be passed to the JVM in order for it to know that this reflection is intended. For some reason I'm not being able to figure out a couple of things which are:

  • Where should this flag be passed? (Through MAVEN_OPTS, as a Maven argument such as -DargLine, in the Dockerfile, etc...)

  • What should the --add-opens flag look like? (I've tried --add-opens java.base/java.lang=ALL-UNNAMED which doesn't make sense to me since I think I should be referencing the Jackson module which I can't find because the documentation is scattered everywhere and not helpful

These are the sources that I took a look at before coming here for help:

PS: If the answers could include an explanation of how you formulated the --add-opens flag to properly solve the warning messages I would be very thankful because I've been trying to understand this for a while now but with no success.





Java Annotation Processor handle modified source code positions

I'm writing custom annotation processor and got struggling with code elements' positions.

Imagine I have the code:

    public class DummyStepClass {

        @Step
        public void getInfo() throws Exception {
            HttpClient client = HttpClient.newBuilder().build();
            @Remember("REQUEST") HttpRequest request = HttpRequest.newBuilder()
                    .uri(new URI("https://postman-echo.com/get"))
                    .GET()
                    .build();
            @Remember("RESPONSE") HttpResponse<String> response = 
                    client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println(response.statusCode());
            System.out.println(response.body());
        }
    }

Purpose of annotation is to save variable into context of a program flow through my steps.

Context class:

    public class Context {

        private static final HashMap<String, Object> storage = new LinkedHashMap<>();

        private Context() {}

        public static void save(String k, Object v) {
            storage.put(k, v);
        }
    }

Literally I want to achieve invoking Context.save(k, v); when annotated rather than writing it every time.

So as a result I want to have something like this:

    public class DummyStepClass {

        @Step
        public void getInfo() throws Exception {
            HttpClient client = HttpClient.newBuilder().build();
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(new URI("https://postman-echo.com/get"))
                    .GET()
                    .build();
            Context.save("REQUEST", request);
            HttpResponse<String> response =
                    client.send(request, HttpResponse.BodyHandlers.ofString());
            Context.save("RESPONSE", request);
            System.out.println(response.statusCode());
            System.out.println(response.body());
    }
}

I do generate this lines of code and they appears in .class files. However this two statements are added in the end of a method.

How can I handle this?





How can I make this reflection code work for any specific case of a generic type?

I have some data coming from some system via a TcpClient.

The system is a kind of column store with it's own way of representing null values. The system supports null for any type including int, DateTime etc.

The TcpClient returns values like DateTime.MinValue in case of nulls. But the client also has a null checking utility.

I have put together some reflection code to generate types, which works fine as long as I don't have any option types. I want to adapt this code to map null values to Option<'t>.

So far, I have the following utility.

let checkNull (x:obj) =
    let elementType = x.GetType()
    let defType = typedefof<ValueOption<_>>;
    let genericType = defType.MakeGenericType elementType
    let optionCaseInfoSome, _ = FSharpValue.GetUnionFields(DateTime.Now |> ValueSome :> obj, genericType)
    let valueNone:ValueOption<DateTime> = ValueNone
    let optionCaseInfoNone, _ = FSharpValue.GetUnionFields(valueNone :> obj, genericType)
    if KdbConstants.IsNull x then
        FSharpValue.MakeUnion(optionCaseInfoNone, Array.empty)
    else
        FSharpValue.MakeUnion(optionCaseInfoSome, [|x|])

This will only work for Option<DateTime> values. How can I adapt this to work for any Option<t>`?

PS: I am aware that my utility is not efficient and much of the values can be pre-calculated, rather than being run each time the function is called. I will clean it up once I get it to work.





Proxy js object: where are defined arguments when calling a function using Reflect.get()

Trying to understand the internals of Proxy and Reflect built-in objects, I've reached - IMO - an interesting "how does this even work" point:

Let's say I want to wrap into a Proxy this object and detect when we're accessing a callable property:

const obj = {
 v: 42,
 foo(n) { return this.v + n }
} 
const pObj = new Proxy(obj, {
  get(target, prop, r) {
    if (typeof target[prop] === 'function') {
      console.log('accessing a function, arguments: ', { ...arguments })
    }
    return Reflect.get(...arguments);
  }
}) 

This code just works:

pObj.foo(1000) // « 1042

Printing this trace:

trace when calling the function

Which reads: arguments has

  • target ([0]): the object
  • prop ([1]): "foo"
  • receiver ([2]): the proxy object itself.

My question is, where is defined the function argument (1000) that is applied to foo(n)? isn't defined in arguments? is it possible to validate this argument before calling Reflect.get(...arguments)?