Skip to content

dynamodb-enhanced cannot be used with GraalVM 21.1 #2445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Aleksandr-Filichkin opened this issue Apr 29, 2021 · 10 comments
Open

dynamodb-enhanced cannot be used with GraalVM 21.1 #2445

Aleksandr-Filichkin opened this issue Apr 29, 2021 · 10 comments
Labels
dynamodb-enhanced feature-request A feature should be added or improved. graalvm p3 This is a minor priority issue

Comments

@Aleksandr-Filichkin
Copy link

Aleksandr-Filichkin commented Apr 29, 2021

Hi,

I'm trying to compile dynamodb-enhanced client with Graalvm 21.1 and awssdk.version=2.16.50
Here the code:
DynamoDbTable<Book> dynamoDbTable = dynamoDbEnhancedClient.table(TABLE_NAME, TableSchema.fromBean(Book.class));

Reflection config doesn't help. I generated native-image artifacts with -agentlib: but it still doesn't help.
GraalVM 21.1 supports Method Handler, I hope it can be fixed.
https://github.com/aws/aws-sdk-java-v2/blob/master/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/mapper/LambdaToMethodBridgeBuilder.java#L76

Error:
Exception in thread "main" java.lang.ExceptionInInitializerError at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:315) Caused by: java.lang.IllegalArgumentException: Failed to generate method handle. at software.amazon.awssdk.enhanced.dynamodb.internal.mapper.LambdaToMethodBridgeBuilder.build(LambdaToMethodBridgeBuilder.java:92) at software.amazon.awssdk.enhanced.dynamodb.internal.mapper.ObjectConstructor.create(ObjectConstructor.java:37) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.newObjectSupplierForClass(BeanTableSchema.java:361) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.createStaticTableSchema(BeanTableSchema.java:172) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.create(BeanTableSchema.java:129) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.create(BeanTableSchema.java:121) at software.amazon.awssdk.enhanced.dynamodb.TableSchema.fromBean(TableSchema.java:81) at com.filichkin.blog.lambda.v3.handler.test.Main.initDispatcher(Main.java:39)

No problem with simple dynamoDb client, it can be compiled with GraalVM

@Aleksandr-Filichkin Aleksandr-Filichkin added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Apr 29, 2021
@zoewangg
Copy link
Contributor

Hi @Aleksandr-Filichkin thanks for reporting the issue. We will investigate to see if we can fix it for BeanTableSchema. I should note that StaticTableSchema might work better for GraalVM native image since it doesn't involve any reflections.

Test code:

private static final TableSchema<Record> TABLE_SCHEMA =
StaticTableSchema.builder(Record.class)
.newItemSupplier(Record::new)
.addAttribute(String.class, a -> a.name("id")
.getter(Record::getId)
.setter(Record::setId)
.tags(primaryPartitionKey()))
.addAttribute(String.class, a -> a.name("sort")
.getter(Record::getSort)
.setter(Record::setSort)
.tags(primarySortKey()))
.addAttribute(String.class, a -> a.name("attribute")
.getter(Record::getAttribute)
.setter(Record::setAttribute))
.addAttribute(String.class, a -> a.name("attribute2*")
.getter(Record::getAttribute2)
.setter(Record::setAttribute2)
.tags(secondaryPartitionKey("gsi_1")))
.addAttribute(String.class, a -> a.name(ATTRIBUTE_NAME_WITH_SPECIAL_CHARACTERS)
.getter(Record::getAttribute3)
.setter(Record::setAttribute3)
.tags(secondarySortKey("gsi_1")))
.build();

@zoewangg zoewangg removed the needs-triage This issue or PR still needs to be triaged. label Apr 29, 2021
@Aleksandr-Filichkin
Copy link
Author

Thank you @zoewangg !
An appropriate issue was created for GraalVM
oracle/graal#3386

@zoewangg zoewangg added feature-request A feature should be added or improved. and removed bug This issue is a bug. labels May 7, 2021
@Nithanim
Copy link

Hello!
I am currently looking to make dynamodb-enhanced (specifically the BeanTableSchema) compatible with graalvm native image and quarkus.

I looked into this issue and found out that the error message is misleading. The problem has nothing to do with MethodHandles (they are fully supported) but rather with using the LambdaMetafactory. Behind the scenes it creates a lambda class which is then attempted to be loaded but loading a class is not possible because everything in a native image is pre-compiled.

My solution to this problem currently is to substitute the use of the LambdaMetafactory for the native-image with a MethodHandle and an inner class which seems to work fine (minus the likely performance hit).

While trying to fix this particular problem I stumbled upon another issue with the LambdaToMethodBridgeBuilder. It uses the Lookup wrong and crashes if the bean class is loaded in a different classloader than the AWS SDK, but this is probably better dicussed in another issue.

I have made a proof of concept as quarkus extension which at least seems to work for my very basic test case https://github.com/Nithanim/quarkus-dynamodb-enhanced.

@deandelponte
Copy link

As a workaround, I've been able to use StaticTableSchema for mapping simple objects, but run into issues when mapping more complex attributes. For example, how would I map something like this using StaticTableSchema?

Please note, CustomerOrgData is a bean and all fields are Strings.

@DynamoDbBean
public class CustomerData {
  private String id = UUID.randomUUID().toString();
  private String name;
  private String description;
  private List<CustomerOrgData> customerOrgData = new ArrayList<CustomerOrgData>();

  @DynamoDbPartitionKey
  public String getId() {
    return id;
  }

  public void setId(@NonNull @NotBlank String id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(@NonNull @NotBlank String name) {
    this.name = name;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public List<CustomerOrgData> getCustomerOrgData() {
    if (customerOrgData == null || customerOrgData.isEmpty()) {
      return new ArrayList<>();
    }
    return CustomerDataUtils.sortCustomerOrgData(customerOrgData);
  }

  public void setCustomerOrgData(List<CustomerOrgData> customerOrgData) {
    this.customerOrgData = customerOrgData;
  }

  public void addCustomerOrgData(CustomerOrgData customerOrgData) {
    this.customerOrgData.add(customerOrgData);
  }
}

@madeupname
Copy link

Assume this is still an issue? I'm looking to convert a project using DynamoDB mapper, but used the Java SDK v1. I want to move it to GraalVM and it seems v2 SDK is the only option. The open question about creating tables seems to be the only concern, but I'm not sure if it actually blocks anything.

@deandelponte did you find a workaround? I haven't really explored SDK 2, but I had a similar mapping where Customer had List<Charge> charges. In my case, "Customer has Charges" is a 1:many composition relationship, not association or aggregation - there is no separate table for Charge. It's also not involved in queries, so it does not need to be specified in the schema. All it needed was:

    public static final String CHARGES = "CHARGES";

    @DynamoDBAttribute(attributeName = CHARGES)
    @DynamoDBTypeConvertedJson
    public List<Charge> getCharges() {
        return charges;
    }

Is your example different? If not, I think it would simply leave out CustomerOrgData from the schema altogether. But I don't know if the BeanTableSchema is doing something special for collections.

@EdWrld
Copy link

EdWrld commented Jan 27, 2023

Hi,
I believe I was running into a similar issue with the BeanTableSchema, switching to StaticTableSchema worked for me; However, I was lucky that the library that was causing me this issue was under my control. If someone is to run into a similiar situation and isn't as lucky; my suggestion would be to try implementing the StaticTableSchema in a GRAALVM Substition method https://blog.frankel.ch/solving-substitution-graalvm-issue/
2023-01-26 21:08:50,546 ERROR [io.qua.ama.lam.run.AbstractLambdaPollLoop] (Lambda Thread (NORMAL)) Failed to run lambda (NORMAL): java.lang.IllegalStateException: GraalVM Substitution: Unable to convert Constructor to MethodHandle at io.quarkus.amazon.dynamodb.enhanced.runtime.BeanTableSchemaSubstitutionImplementation.newObjectSupplierForClass(BeanTableSchemaSubstitutionImplementation.java:24) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.newObjectSupplierForClass(BeanTableSchema.java) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.createStaticTableSchema(BeanTableSchema.java:182) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.create(BeanTableSchema.java:138) at software.amazon.awssdk.enhanced.dynamodb.mapper.BeanTableSchema.create(BeanTableSchema.java:129) at software.amazon.awssdk.enhanced.dynamodb.TableSchema.fromBean(TableSchema.java:83)

@madeupname this link was a pretty good reference that helped me out https://stackoverflow.com/questions/71573650/nested-beans-with-statictableschema-enhanced-dynamodb-client-from-aws-java-sdk

@OmerShemesh
Copy link

Has anyone found any solution to this? :(

@jpOlivo-uala
Copy link

Has anyone found any solution to this?

@Duduxs
Copy link

Duduxs commented Oct 8, 2024

Any solution???

@jpOlivo-uala
Copy link

Any solution???

switching to StaticTableSchema as suggested above worked for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dynamodb-enhanced feature-request A feature should be added or improved. graalvm p3 This is a minor priority issue
Projects
None yet
Development

No branches or pull requests