Skip to content

Commit 785572d

Browse files
authored
feat(scala): support scala native image build (#1922)
## What does this PR do? This PR supports scala native image build and fix quarkus graalvm build for java in quarkiverse/quarkus-fury#7: ``` Error: Class initialization of org.apache.fury.type.ScalaTypes failed. Use the option '--initialize-at-run-time=org.apache.fury.type.ScalaTypes' to explicitly request initialization of this class at run time. com.oracle.svm.core.util.UserError$UserException: Class initialization of org.apache.fury.type.ScalaTypes failed. Use the option '--initialize-at-run-time=org.apache.fury.type.ScalaTypes' to explicitly request initialization of this class at run time. at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.UserError.abort(UserError.java:85) at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.ensureClassInitialized(ClassInitializationSupport.java:195) at .................. org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.ensureClassInitialized(ClassInitializationSupport.java:177) ... 43 more Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: scala.collection.Iterable at org.apache.fury.reflect.ReflectionUtils.loadClass(ReflectionUtils.java:649) at org.apache.fury.type.ScalaTypes.<clinit>(ScalaTypes.java:40) ... 46 more Caused by: java.lang.ClassNotFoundException: scala.collection.Iterable at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.loadClass(NativeImageClassLoader.java:637) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) at org.apache.fury.reflect.ReflectionUtils.loadClass(ReflectionUtils.java:646) ... 47 more ``` ## Related issues Closes quarkiverse/quarkus-fury#7 ## Does this PR introduce any user-facing change? <!-- If any user-facing interface changes, please [open an issue](https://github.com/apache/fury/issues/new/choose) describing the need to do so and update the document if necessary. --> - [ ] Does this PR introduce any public API change? - [ ] Does this PR introduce any binary protocol compatibility change? ## Benchmark <!-- When the PR has an impact on performance (if you don't know whether the PR will have an impact on performance, you can submit the PR first, and if it will have impact on performance, the code reviewer will explain it), be sure to attach a benchmark data here. -->
1 parent fa22801 commit 785572d

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

java/fury-core/src/main/java/org/apache/fury/type/ScalaTypes.java

+42-19
Original file line numberDiff line numberDiff line change
@@ -28,41 +28,64 @@
2828
/** Scala types utils using reflection without dependency on scala library. */
2929
@SuppressWarnings({"unchecked", "rawtypes"})
3030
public class ScalaTypes {
31-
private static final Class<?> SCALA_MAP_TYPE;
32-
private static final Class<?> SCALA_SEQ_TYPE;
33-
private static final Class<?> SCALA_ITERABLE_TYPE;
34-
private static final Class<?> SCALA_ITERATOR_TYPE;
35-
private static final java.lang.reflect.Type SCALA_ITERATOR_RETURN_TYPE;
36-
private static final java.lang.reflect.Type SCALA_NEXT_RETURN_TYPE;
31+
private static volatile Class<?> SCALA_MAP_TYPE;
32+
private static volatile Class<?> SCALA_SEQ_TYPE;
33+
private static volatile Class<?> SCALA_ITERABLE_TYPE;
34+
private static volatile java.lang.reflect.Type SCALA_ITERATOR_RETURN_TYPE;
35+
private static volatile java.lang.reflect.Type SCALA_NEXT_RETURN_TYPE;
3736

38-
static {
39-
try {
40-
SCALA_ITERABLE_TYPE = ReflectionUtils.loadClass("scala.collection.Iterable");
41-
SCALA_ITERATOR_TYPE = ReflectionUtils.loadClass("scala.collection.Iterator");
37+
public static Class<?> getScalaMapType() {
38+
if (SCALA_MAP_TYPE == null) {
39+
// load scala classes dynamically to make graalvm native build work
40+
// see https://github.com/quarkiverse/quarkus-fury/issues/7
4241
SCALA_MAP_TYPE = ReflectionUtils.loadClass("scala.collection.Map");
43-
SCALA_SEQ_TYPE = ReflectionUtils.loadClass("scala.collection.Seq");
44-
SCALA_ITERATOR_RETURN_TYPE = SCALA_ITERABLE_TYPE.getMethod("iterator").getGenericReturnType();
45-
SCALA_NEXT_RETURN_TYPE = SCALA_ITERATOR_TYPE.getMethod("next").getGenericReturnType();
46-
} catch (NoSuchMethodException e) {
47-
throw new RuntimeException(e);
4842
}
49-
}
50-
51-
public static Class<?> getScalaMapType() {
5243
return SCALA_MAP_TYPE;
5344
}
5445

5546
public static Class<?> getScalaSeqType() {
47+
if (SCALA_SEQ_TYPE == null) {
48+
SCALA_SEQ_TYPE = ReflectionUtils.loadClass("scala.collection.Seq");
49+
}
5650
return SCALA_SEQ_TYPE;
5751
}
5852

5953
public static Class<?> getScalaIterableType() {
54+
if (SCALA_ITERABLE_TYPE == null) {
55+
SCALA_ITERABLE_TYPE = ReflectionUtils.loadClass("scala.collection.Iterable");
56+
}
6057
return SCALA_ITERABLE_TYPE;
6158
}
6259

6360
public static TypeRef<?> getElementType(TypeRef typeRef) {
6461
TypeRef<?> supertype = typeRef.getSupertype(getScalaIterableType());
65-
return supertype.resolveType(SCALA_ITERATOR_RETURN_TYPE).resolveType(SCALA_NEXT_RETURN_TYPE);
62+
return supertype
63+
.resolveType(getScalaIteratorReturnType())
64+
.resolveType(getScalaNextReturnType());
65+
}
66+
67+
private static Type getScalaIteratorReturnType() {
68+
if (SCALA_ITERATOR_RETURN_TYPE == null) {
69+
try {
70+
SCALA_ITERATOR_RETURN_TYPE =
71+
getScalaIterableType().getMethod("iterator").getGenericReturnType();
72+
} catch (NoSuchMethodException e) {
73+
throw new RuntimeException(e);
74+
}
75+
}
76+
return SCALA_ITERATOR_RETURN_TYPE;
77+
}
78+
79+
private static Type getScalaNextReturnType() {
80+
if (SCALA_NEXT_RETURN_TYPE == null) {
81+
Class<?> scalaIteratorType = ReflectionUtils.loadClass("scala.collection.Iterator");
82+
try {
83+
SCALA_NEXT_RETURN_TYPE = scalaIteratorType.getMethod("next").getGenericReturnType();
84+
} catch (NoSuchMethodException e) {
85+
throw new RuntimeException(e);
86+
}
87+
}
88+
return SCALA_NEXT_RETURN_TYPE;
6689
}
6790

6891
/** Returns key/value type of scala map. */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
# https://www.graalvm.org/latest/reference-manual/native-image/dynamic-features/Reflection/#unsafe-accesses :
19+
# The unsafe offset get on build time may be different from runtime
20+
Args=--initialize-at-build-time=org.apache.fury.type.ScalaTypes,\
21+
org.apache.fury.type.Seq,\
22+
org.apache.fury.type.Map,\
23+
org.apache.fury.type.Iterable,\
24+
scala.collection.Iterator,\
25+
org.apache.fury.serializer.scala.ScalaDispatcher,\
26+
org.apache.fury.serializer.scala.AbstractScalaCollectionSerializer,\
27+
org.apache.fury.serializer.scala.AbstractScalaMapSerializer,\
28+
org.apache.fury.serializer.scala.ScalaSortedMapSerializer,\
29+
org.apache.fury.serializer.scala.ScalaMapSerializer,\
30+
org.apache.fury.serializer.scala.ScalaSortedSetSerializer,\
31+
org.apache.fury.serializer.scala.ScalaSeqSerializer,\
32+
org.apache.fury.serializer.scala.ScalaCollectionSerializer,\
33+
org.apache.fury.serializer.scala.RangeSerializer,\
34+
org.apache.fury.serializer.scala.RangeUtils$,\
35+
org.apache.fury.serializer.scala.NumericRangeSerializer

0 commit comments

Comments
 (0)