-
Notifications
You must be signed in to change notification settings - Fork 245
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
fix(java): compilation fails with "code too large" #1605
Conversation
In cases where a module includes a large amount of types, compilation of Java packages could fail with the "code too large" error. This is due to the presence of a single method in the `$Module` class that contains a reference to all types in the package, resulting in a large amount of generated bytecode (more than Java's maximum of 64KB). In order to remediate, moved the FQN to Class mapping to a resource file that gets loaded when the `$Module` class is initialized. The individual `Class` entries are then resolved at the last minute using `Class.forName` to ensure the reoslution happens *after* the full mapping has been processed.
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Thank you for contributing! ❤️ I will now look into making sure the PR is up-to-date, then proceed to try and merge it! |
Merging (with squash)... |
private static final Map<String, String> MODULE_TYPES = load(); | ||
|
||
private static Map<String, String> load() { | ||
final Map<String, String> result = new HashMap<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably makes sense to implement this in JsiiModule
, no?
…ion (#1706) --- Java generated modules use cache to store the result of `resolveClass` which is called when ever `jsiiStaticGet`/`jsiiGet` is called. The cache is implemented as a `HashMap`, to fill the cache we use `computeIfAbsent`: ```Java this.cache.computeIfAbsent(MODULE_TYPES.get(fqn), this::findClass); ``` > [code](https://github.com/aws/jsii/blob/master/packages/jsii-pacmak/lib/targets/java.ts#L2533) When either of the get methods is called on a type which in itself includes a type, the first get (the root type get) will call get on the inner type. When `computeIfAbsent` is called from the root get, the compute method will trigger another call to `computeIfAbsent` to resolve the inner type, since all types share the same cache it means that the inner `computeIfAbsent` call will modify the cache while the root `computeIfAbsent` is not yet completed, resulting it a `ConcurrentModificationException`. This effects all Java >= 9 applications as a change to the behavior of `computeIfAbsent` was introduced in Java 9. From the [Javadocs](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html#computeIfAbsent(K,java.util.function.Function)): ``` Throws: ConcurrentModificationException - if it is detected that the mapping function modified this map ``` The use of `computeIfAbsent ` was introduced in #1605 and released in `v1.4.1`. This PR replaces `computeIfAbsent` with explicitly checking if the value exists in the cache and if not adding it (essentially old style `computeIfAbsent`). ### Test Steps to verify fix: 1. Build and package a sample module (see repro) using a local version of `jsii` and `jsii-pacmak`. 2. Add the generated jar to a local `mvn` repo. 3. Added the package as a dependency to a Java11 application. 4. Verify the exception is no longer thrown. ### Repro A repro can be found in this [repo](https://github.com/NetaNir/jsii-nested-get-repro) By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
Commit Message
fix(java): compilation fails with "code too large" (#1605)
In cases where a module includes a large amount of types, compilation of
Java packages could fail with the "code too large" error. This is due to
the presence of a single method in the
$Module
class that contains areference to all types in the package, resulting in a large amount of
generated bytecode (more than Java's maximum of 64KB).
In order to remediate, moved the FQN to Class mapping to a resource file
that gets loaded when the
$Module
class is initialized. The individualClass
entries are then resolved at the last minute usingClass.forName
to ensure the reoslution happens after the fullmapping has been processed.
End Commit Message
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.