jeudi 6 avril 2023

Method to Serialize and Deserialize an Object using java.lang.reflect (Java)

I'm trying to make a method in Java that allows me to convert an Object's constructor and the values used in the constructor into a String and convert the String into a method that deserializes the String and converts the String to the selected Object using the newInstance() method in the java.lang.reflect.Constructor class. I want to try an serialize an Object that doesn't implement the Serializable interface.

The way I figured I would do this is using the java.lang.reflect package and making a method that would act as an outside toString() method that takes in an Object and the parameters of the Object in the form of a Class<?>, but I don't know how to recieve the variables used to make the Object. For example, take this User object:

class User {
    private final String username;
    private int userID;
    public User(String username, int userID) {
        if (!validateUserID(userID)) {
            throw new RuntimeException("ID cannot have more or less than 6 digits!" + this.userID);
        }
        this.username = username;
        this.userID = userID;
    }
    private boolean validateUserID(int userID){
        return String.valueOf(userID).length() == 6;
    }
}

If I were to serialize this User object initialized as User user = new User("username", 985313);, I want to get the name of the class, the constructor of the class, the parameters of the class in the form of Class<?>..., and the variables used to initialize this Object. How would I go about doing this?





Dynamic subscription to event at runtime

I have implemented a very simple example on how I would want to subscribe dynamically to external events and perform some specific logic when the event is raised:

public static class ConsoleHost
{
    // Hooks onto an external event to automatically output a simple message
    public static void RegisterHook<TEventArgs>(object obj, string eventName, string message)
        where TEventArgs : EventArgs
    {
        // Create Dynamic Method
        var dynMethod = CreateHandler<TEventArgs>(() =>
        {
            Write(message);
        });
        
        // Retreive Method
        var methodInfo = dynMethod.GetMethodInfo();

        // Retreive EventInfo
        var eventInfo = obj.GetType().GetEvent(eventName);

        // Build dynamic delegate
        var dynDelegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, methodInfo); // <-- This fails cause of different signatures

        // Finally add EventHandler
        eventInfo.AddEventHandler(obj, dynDelegate);
    }

    // Generate Proxy EventHandler
    private static EventHandler<TEventArgs> CreateHandler<TEventArgs>(Action action)
        where TEventArgs : EventArgs
    {
        return (object? sender, TEventArgs e) => action();
    }

    // Simple Output to Console for Example Purposes
    public static void Write(string message)
    {
        Console.WriteLine(message);
    }
}

However I get an error stating, that my dynamic method has a different signature than expected. What am I missing?





How to extract type parameters using reflection

Context: I'm writing a generic auto-mapper that takes two types of structs, checks each field of said structs for a given tag, then copies the value from the source struct to the target struct assuming that they have matching tags and types. Whenever a struct field is another (nested) struct, I want the auto-mapper function to do a recursive call, auto-mapping all the way down the rabbit hole.

Problem: I'm only able to pass the concrete type of the root structs. Once I'm inside the generic function that's using reflection, trying to extract the nested struct types doesn't seem possible. While I can pass the Value.Interface() as an argument, I still need to pass the type parameters as well.

Here is some simplified code to show the problem.

type Alpha struct {
    Nested Beta `automap:"nested"`
}

type Beta struct {
    Info string `automap:"info"`
}

type Foo struct {
    Nested Bar `automap:"nested"`
}

type Bar struct {
    Info string `automap:"info"`
}

func TestAutoMap(t *testing.T) {

    b := Beta{Info: "Hello from Beta!"}
    a := Alpha{Nested: b}

    f, err := AutoMap[Alpha, Foo](a)
    if err != nil {
        fmt.Println(err)
        t.Fail()
    }
    fmt.Println("f.nested.info:", f.Nested.Info)
}

func AutoMap[S, T any](source S) (target T, err error) {

    targetStruct := reflect.ValueOf(&target).Elem()
    sourceStruct := reflect.ValueOf(&source).Elem()

    // .Type and .Kind directly did not work.
    nestedSourceType := ??? // I want this to be type Beta.
    nestedTargetType := ??? // I want this to be type Bar.

    sourceInterface := sourceStruct.Interface()

    t, err := AutoMap[nestedSourceType, nestedTargetType](sourceInterface)
    if err != nil {
        return target, err
    }
    target = t

    return target, nil
}




mercredi 5 avril 2023

The interface{} in golang confused me

everyone. If i have the following code. Why it will raise a error:

The code:

var i interface{}
v, ok :=i.(interface{})
fmt.Println(v, ok)

The error: <nil> false

Whether the dynamic type of a declarated interface{} var is nil alaways? but when it will be interface{}? What will be false any var's assertion to interface{} forever?





mardi 4 avril 2023

Kotlin enum via reflection

I wonder is there any better way to parse enum when you don't have Generic and have only KProperty1<T, *>?

I have found / come up with solution like this:

enum Car {
    BMW, AUDI
}

val property = properties[fieldName] as? KProperty1<T, *>
val instanceKClass = property.returnType.jvmErasure

if (instanceKClass.java.isEnum) {
   parseEnum(property.javaField!!.type as Class<Enum<*>>, "BMW")
}


fun parseEnum(enumClass: Class<Enum<*>>, value: Any?): Enum<*>? {
    val enumClz = enumClass.enumConstants
    return try {
       enumClz.first { it.name == value }
    } catch (ignored: Exception) {
       throw IlligalArgumentException("there is no such enum")
    }
}

I'm trying to extract enum value from string in Kotlin via reflection and I want to find best possible way of doing this

P.S. I'm looking for advice how to do it more efficient and nice, because I'm not really satisfied with this way.





lundi 3 avril 2023

C# Build anonymous type from array string

I'm looking for a way to build an anonymous type from an object where it's property names match those in a given string array. Something like:

//Current Way:
    var anonObject = primaryObject.Select(m=> new {m.property1, m.property2, m.property3, m.property4, ...etc});
//Ideal Way:
    var propertyArray= new string["property1","property3"];
    var anonObject = primaryObject.Select(m=> new { /* Something here where we step through primaryObject.GetProperties() and only choose the ones where the name is contained in the above array */ });

Any ideas on how to achieve this?





dimanche 2 avril 2023

Reflection getMethod(...) throws NoSuchMethodException with a different method name

Using myClass.getMethod("func_181057_v") throws exception in the console - "NoSuchMethodException: myClass.v()".
Why is the method name different in thrown exception compared to what I've actually typed in and how can I retrieve that method?

I have tried both .getMethod(..) and .getDelcaredMethod(..) as well as printed .getDeclaredMethods() list and .func_181057_v() was on the list.

My code:

try {
   Class<?> fmlCommonHandlerClass = Class.forName("net.minecraftforge.fml.common.FMLCommonHandler");
   Class<?> minecraftServerClass = Class.forName("net.minecraft.server.MinecraftServer");
   Class<?> playerListClass = Class.forName("net.minecraft.server.management.PlayerList");

   Method getMinecraftServerInstanceMethod = fmlCommonHandlerClass.getDeclaredMethod("getMinecraftServerInstance");
   Method getPlayerListMethod = minecraftServerClass.getDeclaredMethod("getPlayerList");
   Method getPlayersMethod = playerListClass.getMethod("func_181057_v");
} catch (Exception exception) {
   throw new RuntimeException(exception);
}

Exact method name is public java.util.List net.minecraft.server.management.PlayerList.func_181057_v()
If you want to execute it you need to compile and install it as a plugin to Mohist server, I'm using version 1.12.2, build 320.

Full exception:

[18:25:56 ERROR]: Error occurred while enabling ReflectionExample v1.0-SNAPSHOT (Is it up to date?)
 java.lang.RuntimeException: java.lang.NoSuchMethodException: net.minecraft.server.management.PlayerList.v()
        at com.example.plugin.reflectionExample.ReflectionExample.onEnable(ReflectionExample.java:20) ~[?:?]
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:177) ~[JavaPlugin.class:?]
        at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:318) [JavaPluginLoader.class:?]
        at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:399) [SimplePluginManager.class:?]
        at org.bukkit.craftbukkit.v1_12_R1.CraftServer.enablePlugin(CraftServer.java:477) [CraftServer.class:?]
        at org.bukkit.craftbukkit.v1_12_R1.CraftServer.enablePlugins(CraftServer.java:418) [CraftServer.class:?]
        at net.minecraft.server.MinecraftServer.func_71247_a(MinecraftServer.java:383) [MinecraftServer.class:?]
        at net.minecraft.server.dedicated.DedicatedServer.func_71197_b(DedicatedServer.java:315) [nz.class:?]
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:590) [MinecraftServer.class:?]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_361]
Caused by: java.lang.NoSuchMethodException: net.minecraft.server.management.PlayerList.v()
        at java.lang.Class.getMethod(Unknown Source) ~[?:1.8.0_361]
        at com.mohistmc.bukkit.nms.proxy.ProxyClass.getMethod(ProxyClass.java:43) ~[ProxyClass.class:?]
        at com.example.plugin.reflectionExample.ReflectionExample.onEnable(ReflectionExample.java:18) ~[?:?]
        ... 9 more