Skip to content

Commit 6ce169e

Browse files
authored
Fix rdf validate command in AoT builds (#211)
* Fix rdf validate command in AoT builds We substituted the whole class instead of a single method... I've found a better way around this, removing SecureRandom entirely. This reduces binary size from 65.11 MB to 63.96 MB. Incidental win, yay. * fix
1 parent 3243ecb commit 6ce169e

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

.github/workflows/aot-test.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ jobs:
4141
target/graalvm-native-image/jelly-cli version | grep "JVM reflection: supported"
4242
4343
# Test RDF conversions
44-
echo '_:b <http://t.org/> _:b .' | target/graalvm-native-image/jelly-cli \
45-
rdf to-jelly --in-format=nt > out.jelly && \
44+
echo '_:b <http://t.org/> _:b .' > in.nt
45+
target/graalvm-native-image/jelly-cli \
46+
rdf to-jelly --in-format=nt in.nt > out.jelly && \
4647
[ -s out.jelly ]
4748
target/graalvm-native-image/jelly-cli \
4849
rdf from-jelly --out-format=jelly-text out.jelly > out.txt && \
@@ -56,6 +57,10 @@ jobs:
5657
echo '<?xml version="1.0"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Seq rdf:about="http://example.org/favourite-fruit"></rdf:Seq></rdf:RDF>' | \
5758
target/graalvm-native-image/jelly-cli rdf to-jelly --in-format "rdfxml" > rdfxml.jelly && \
5859
[ -s rdfxml.jelly ]
60+
61+
# Test rdf validate
62+
target/graalvm-native-image/jelly-cli \
63+
rdf validate out.jelly --compare-to-rdf-file in.nt
5964
6065
- name: Upload binary
6166
uses: actions/upload-artifact@v4

build.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ lazy val graalOptions = Seq(
3434
"--initialize-at-build-time=org.glassfish.json.UnicodeDetectingInputStream",
3535
"-H:+TrackPrimitiveValues", // SkipFlow optimization -- will be default in GraalVM 25
3636
"-H:+UsePredicates", // SkipFlow optimization -- will be default in GraalVM 25
37+
// Make sure we don't include stuff that should be unreachable in the native image
38+
"-H:AbortOnMethodReachable=*UUID.randomUUID*",
3739
)
3840

3941
lazy val TestSerial = config("test-serial") extend Test

src/main/java/eu/neverblink/jelly/cli/graal/GraalSubstitutes.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
import java.net.URI;
1111
import java.nio.charset.Charset;
12-
import java.security.Provider;
13-
import java.util.List;
12+
import java.util.UUID;
13+
import java.util.concurrent.ThreadLocalRandom;
1414

1515
// Substitutions of classes and methods for GraalVM native image builds.
1616
// These try to remove things from the static analysis (and, in effect, from the final binary)
@@ -53,14 +53,33 @@ final class HttpLibSubstitute { }
5353
final class HttpEnvSubstitute { }
5454

5555
/**
56-
* UUID generation is used by Jena for blank node IDs, but we can fall back to the default implementation.
56+
* Use pseudo-random UUIDs instead of secure random ones for seeding the blank node allocator.
57+
* The secure random number generation pulls in a lot of stuff we don't need.
58+
* <p>
59+
* For conversion commands, this is not used at all, because we preserve blank node IDs.
5760
*/
58-
@Substitute
59-
@TargetClass(className = "sun.security.jca.ProviderList")
60-
final class ProviderListSubstitute {
61+
@TargetClass(org.apache.jena.riot.lang.BlankNodeAllocatorHash.class)
62+
final class BlankNodeAllocatorHashSubstitute {
63+
@Substitute
64+
UUID freshSeed() {
65+
ThreadLocalRandom r = ThreadLocalRandom.current();
66+
return new UUID(r.nextLong(), r.nextLong());
67+
}
68+
}
69+
70+
/**
71+
* Jena uses secure random number generation to create blank node IDs in its Model API.
72+
* <p>
73+
* Replaced with pseudo-random UUIDs to avoid including secure random number generation in the native image.
74+
* This should be good enough for our purposes, because this is only used in init code for vocabularies
75+
* and not for user data.
76+
*/
77+
@TargetClass(org.apache.jena.graph.BlankNodeId.class)
78+
final class BlankNodeIdSubstitute {
6179
@Substitute
62-
public List<Provider> providers() {
63-
return List.of();
80+
public static String createFreshId() {
81+
ThreadLocalRandom r = ThreadLocalRandom.current();
82+
return new UUID(r.nextLong(), r.nextLong()).toString();
6483
}
6584
}
6685

0 commit comments

Comments
 (0)