j4rs icon indicating copy to clipboard operation
j4rs copied to clipboard

Incorrect constructor selected

Open rukai opened this issue 1 year ago • 2 comments

I am using j4rs to test the java kafka driver against my application.

I have the following code:

use j4rs::{InvocationArg, Jvm, JvmBuilder, MavenArtifact};

fn main() {
    let jvm: Jvm = JvmBuilder::new().build().unwrap();

    jvm.deploy_artifact(&MavenArtifact::from("org.apache.kafka:kafka-clients:3.7.0"))
        .unwrap();
    jvm.deploy_artifact(&MavenArtifact::from("org.slf4j:slf4j-api:1.7.36"))
        .unwrap();
    jvm.deploy_artifact(&MavenArtifact::from("org.slf4j:slf4j-simple:1.7.36"))
        .unwrap();

    jvm.create_instance(
        "org.apache.kafka.clients.admin.NewTopic",
        &[
            InvocationArg::try_from("partitions1").unwrap(),
            InvocationArg::try_from(1_i32)
                .unwrap()
                .into_primitive()
                .unwrap(),
            InvocationArg::try_from(1_i16)
                .unwrap()
                .into_primitive()
                .unwrap(),
        ],
    )
    .unwrap();

    println!("Success");
}

It creates a NewTopic as documented here: https://docs.confluent.io/platform/current/clients/javadocs/javadoc/org/apache/kafka/clients/admin/NewTopic.html And the source code is here: https://github.com/a0x8o/kafka/blob/master/clients/src/main/java/org/apache/kafka/clients/admin/NewTopic.java

The correct constructor here is NewTopic(String name, int numPartitions, short replicationFactor). In my test this constructor will often be selected. However sometimes it will instead select the constructor: NewTopic(String name, Optional<Integer> numPartitions, Optional<Short> replicationFactor)

In the code snippet I pasted, it seems to always select the incorrect constructor, but given the non-deterministic nature of the problem it might behave differently on your machine.

When the code snippet is run I get the following error:

Exception in thread "main" org.astonbitecode.j4rs.errors.InstantiationException: Cannot create instance of org.apache.kafka.clients.admin.NewTopic
	at org.astonbitecode.j4rs.api.instantiation.NativeInstantiationImpl.instantiate(NativeInstantiationImpl.java:47)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(Unknown Source)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Unknown Source)
	at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source)
	at org.astonbitecode.j4rs.api.instantiation.NativeInstantiationImpl.createInstance(NativeInstantiationImpl.java:101)
	at org.astonbitecode.j4rs.api.instantiation.NativeInstantiationImpl.instantiate(NativeInstantiationImpl.java:44)
Caused by: java.lang.ClassCastException: Cannot cast java.lang.Short to java.util.Optional
	at java.base/java.lang.Class.cast(Unknown Source)
	... 5 more
thread 'main' panicked at src/main.rs:27:6:
called `Result::unwrap()` on an `Err` value: JavaError("An Exception was thrown by Java... Please check the logs or the console.")
stack backtrace:
   0: rust_begin_unwind
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
   2: core::result::unwrap_failed
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1649:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1073:23
   4: blah::main
             at ./main.rs:13:5
   5: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

rukai avatar Mar 01 '24 03:03 rukai

https://github.com/astonbitecode/j4rs/blob/d361dd00461c8dfd3d0da99096e7eebd8442e434/java/src/main/java/org/astonbitecode/j4rs/api/instantiation/NativeInstantiationImpl.java#L119-L123 The issue seems to be here, any ParameterizedType in a constructor will always match. This must be causing the Optional to always match. The non-deterministic part of the problem is probably because the list of constructors can be in any order.

I think the solution might be to call some of the methods here https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/ParameterizedType.html in order to get at the types making up the ParameterizedType. But I'm not really a java person.

rukai avatar Mar 01 '24 03:03 rukai

Indeed, there was an issue when handling the parameterized types to match constructors. I pushed a fix. Can you please check that it works for you?

Thanks.

astonbitecode avatar Mar 01 '24 08:03 astonbitecode

I can confirm the example I gave works now. I ran it in a loop 100 times for good measure.

Thanks for the quick resolution!

rukai avatar Mar 04 '24 21:03 rukai