Flawed construction of Java objects involving polymorphic Listings #191

Closed
opened 2025-12-30 01:21:55 +01:00 by adam · 4 comments
Owner

Originally created by @elkoDev on GitHub (Jul 24, 2024).

Context

  • Objective: Map polymorphic Listings to Java objects
  • Impact: Polymorphic Listings cannot be mapped
  • Version: Pkl 0.26.2 (Windows 10.0, native)

Steps to reproduce

Given the following module with a polymorphic listing:

abstract class A {}

class B extends A {}

class C extends A {}

class As {
    elements: Listing<A>
}

list: As = new {
    elements {
        new B {}
        new C {}
    }
}

We generate the corresponding Java classes:

java -cp pkl-tools-0.26.2.jar org.pkl.codegen.java.Main -o generated/ Faulty.pkl

We use the ValueMapper to create an object of type As

  var module = module.get("list");
  var list = mapper.map(module, Faulty.As.class);

Error

Exception in thread "main" org.pkl.config.java.mapper.ConversionException: Faulty converting property `elements` in Pkl object of type `Faulty#As` to equally named constructor parameter in Java class `example.Faulty$As`: Faulty accessing constructor `protected example.Faulty$A(long)`.
	at org.pkl.config.java.mapper.PObjectToDataObject$ConverterImpl.convert(PObjectToDataObject.java:218)
	at org.pkl.config.java.mapper.PObjectToDataObject$ConverterImpl.convert(PObjectToDataObject.java:154)
	at org.pkl.config.java.mapper.ValueMapperImpl.map(ValueMapperImpl.java:57)
	at org.pkl.config.java.mapper.ValueMapper.map(ValueMapper.java:51)
	at example.Main.main(Main.java:20)
Caused by: java.lang.IllegalAccessException: member is protected: example.Faulty$A.<init>[Ljava.lang.Object;@7282af25/invokeSpecial, from class org.pkl.config.java.mapper.PObjectToDataObject (unnamed module @19dfb72a)
	at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:894)
	at java.base/java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:3987)
Caused by: java.lang.IllegalAccessException: member is protected: example.Faulty$A.<init>[Ljava.lang.Object;@7282af25/invokeSpecial, from class org.pkl.config.java.mapper.PObjectToDataObject (unnamed module @19dfb72a)

	at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectConstructorCommon(MethodHandles.java:4227)
	at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectConstructorNoSecurityManager(MethodHandles.java:4221)
	at java.base/java.lang.invoke.MethodHandles$Lookup.unreflectConstructor(MethodHandles.java:3534)
	at org.pkl.config.java.mapper.PObjectToDataObject.lambda$create$0(PObjectToDataObject.java:64)
	at java.base/java.util.Optional.map(Optional.java:260)
	at org.pkl.config.java.mapper.PObjectToDataObject.lambda$create$1(PObjectToDataObject.java:60)
	at java.base/java.util.Optional.flatMap(Optional.java:289)
	at org.pkl.config.java.mapper.PObjectToDataObject.create(PObjectToDataObject.java:57)
	at org.pkl.config.java.mapper.ValueMapperImpl.getConverter(ValueMapperImpl.java:107)
	at org.pkl.config.java.mapper.PCollectionToCollection$ConverterImpl.convert(PCollectionToCollection.java:124)
	at org.pkl.config.java.mapper.PCollectionToCollection$ConverterImpl.convert(PCollectionToCollection.java:104)
	at org.pkl.config.java.mapper.PObjectToDataObject$ConverterImpl.convert(PObjectToDataObject.java:207)
	... 4 more
Originally created by @elkoDev on GitHub (Jul 24, 2024). ### Context - Objective: Map polymorphic Listings to Java objects - Impact: Polymorphic Listings cannot be mapped - Version: Pkl 0.26.2 (Windows 10.0, native) #### Steps to reproduce Given the following module with a polymorphic listing: ```pkl abstract class A {} class B extends A {} class C extends A {} class As { elements: Listing<A> } list: As = new { elements { new B {} new C {} } } ``` We generate the corresponding Java classes: ```bash java -cp pkl-tools-0.26.2.jar org.pkl.codegen.java.Main -o generated/ Faulty.pkl ``` We use the ValueMapper to create an object of type `As` ```java var module = module.get("list"); var list = mapper.map(module, Faulty.As.class); ```` #### Error ```bash Exception in thread "main" org.pkl.config.java.mapper.ConversionException: Faulty converting property `elements` in Pkl object of type `Faulty#As` to equally named constructor parameter in Java class `example.Faulty$As`: Faulty accessing constructor `protected example.Faulty$A(long)`. at org.pkl.config.java.mapper.PObjectToDataObject$ConverterImpl.convert(PObjectToDataObject.java:218) at org.pkl.config.java.mapper.PObjectToDataObject$ConverterImpl.convert(PObjectToDataObject.java:154) at org.pkl.config.java.mapper.ValueMapperImpl.map(ValueMapperImpl.java:57) at org.pkl.config.java.mapper.ValueMapper.map(ValueMapper.java:51) at example.Main.main(Main.java:20) Caused by: java.lang.IllegalAccessException: member is protected: example.Faulty$A.<init>[Ljava.lang.Object;@7282af25/invokeSpecial, from class org.pkl.config.java.mapper.PObjectToDataObject (unnamed module @19dfb72a) at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:894) at java.base/java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:3987) Caused by: java.lang.IllegalAccessException: member is protected: example.Faulty$A.<init>[Ljava.lang.Object;@7282af25/invokeSpecial, from class org.pkl.config.java.mapper.PObjectToDataObject (unnamed module @19dfb72a) at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectConstructorCommon(MethodHandles.java:4227) at java.base/java.lang.invoke.MethodHandles$Lookup.getDirectConstructorNoSecurityManager(MethodHandles.java:4221) at java.base/java.lang.invoke.MethodHandles$Lookup.unreflectConstructor(MethodHandles.java:3534) at org.pkl.config.java.mapper.PObjectToDataObject.lambda$create$0(PObjectToDataObject.java:64) at java.base/java.util.Optional.map(Optional.java:260) at org.pkl.config.java.mapper.PObjectToDataObject.lambda$create$1(PObjectToDataObject.java:60) at java.base/java.util.Optional.flatMap(Optional.java:289) at org.pkl.config.java.mapper.PObjectToDataObject.create(PObjectToDataObject.java:57) at org.pkl.config.java.mapper.ValueMapperImpl.getConverter(ValueMapperImpl.java:107) at org.pkl.config.java.mapper.PCollectionToCollection$ConverterImpl.convert(PCollectionToCollection.java:124) at org.pkl.config.java.mapper.PCollectionToCollection$ConverterImpl.convert(PCollectionToCollection.java:104) at org.pkl.config.java.mapper.PObjectToDataObject$ConverterImpl.convert(PObjectToDataObject.java:207) ... 4 more ```
adam closed this issue 2025-12-30 01:21:55 +01:00
Author
Owner

@holzensp commented on GitHub (Jul 24, 2024):

This appears to be a bug. Especially

Faulty accessing constructor protected example.Faulty$A(long)

is surprising.

@holzensp commented on GitHub (Jul 24, 2024): This appears to be a bug. Especially > Faulty accessing constructor `protected example.Faulty$A(long)` is surprising.
Author
Owner

@bioball commented on GitHub (Jul 24, 2024):

I don't think this is a bug; at least, I can't reproduce it here: https://github.com/bioball/pkl-jvm-examples/blob/repro-issue-597/codegen-java/src/main/java/example/JavaCodeGeneratorExample.java

From that error message, it looks like It is trying to initialize A, which probably means that you are not including the generated properties file in your classpath.

The code generator will produce two directories in the output dir; java, and resources. Are you including both of these in your classpath?

@bioball commented on GitHub (Jul 24, 2024): I don't think this is a bug; at least, I can't reproduce it here: https://github.com/bioball/pkl-jvm-examples/blob/repro-issue-597/codegen-java/src/main/java/example/JavaCodeGeneratorExample.java From that error message, it looks like It is trying to initialize `A`, which probably means that you are not including the generated properties file in your classpath. The code generator will produce two directories in the output dir; `java`, and `resources`. Are you including both of these in your classpath?
Author
Owner

@elkoDev commented on GitHub (Jul 24, 2024):

Thank you for the fast response, probably I did not include the properties file to the class path. I think this issue can be closed.

@elkoDev commented on GitHub (Jul 24, 2024): Thank you for the fast response, probably I did not include the properties file to the class path. I think this issue can be closed.
Author
Owner

@bioball commented on GitHub (Jul 24, 2024):

By the way: ValueMapper isn't really meant to be used like this. It's used internally by ConfigEvaluator to map values for you.

The way you'd typically eval into Java is through the as method. For example, something like:

MyConfig getConfig() {
  try (var evaluator = ConfigEvaluator.preconfigured()) {
    return evaluator.evaluate(ModuleSource.modulePath("/foo")).as(MyConfig.class);
  }
}
@bioball commented on GitHub (Jul 24, 2024): By the way: `ValueMapper` isn't really meant to be used like this. It's used internally by `ConfigEvaluator` to map values for you. The way you'd typically eval into Java is through the `as` method. For example, something like: ```java MyConfig getConfig() { try (var evaluator = ConfigEvaluator.preconfigured()) { return evaluator.evaluate(ModuleSource.modulePath("/foo")).as(MyConfig.class); } } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/pkl#191