From f1c7dad4e941b855b8ebd97369ecc7f71338165b Mon Sep 17 00:00:00 2001 From: Kristof Dhondt Date: Mon, 11 Jan 2021 15:03:47 +0100 Subject: [PATCH] serialization registration from inside features --- .../org.graalvm.nativeimage/snapshot.sigtest | 4 + .../hosted/RuntimeSerialization.java | 57 ++++ .../impl/RuntimeSerializationSupport.java | 51 ++++ .../configure/config/ConfigurationSet.java | 2 +- .../config/SerializationConfiguration.java | 100 ++++--- .../SerializationConfigurationType.java | 80 +++++ .../trace/SerializationProcessor.java | 2 +- .../SerializationConfigurationParser.java | 25 +- ...ializationConfigurationParserDelegate.java | 36 +++ .../SerializationDenyConfigurationParser.java | 38 +++ .../config/SerializationRegistryAdapter.java | 59 ++++ .../serialize/SerializationRegistry.java | 2 +- .../serialize/SerializationSupport.java | 1 - .../hosted/SerializationFeature.java | 282 ++++++++++-------- .../serialize/hosted/package-info.java | 30 ++ ...dk_internal_reflect_AccessorGenerator.java | 5 +- 16 files changed, 606 insertions(+), 168 deletions(-) create mode 100644 sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java create mode 100644 sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java create mode 100644 substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParserDelegate.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationDenyConfigurationParser.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/SerializationRegistryAdapter.java rename substratevm/src/{com.oracle.svm.core/src/com/oracle/svm/core/jdk => com.oracle.svm.reflect/src/com/oracle/svm/reflect}/serialize/SerializationRegistry.java (97%) create mode 100644 substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/package-info.java rename substratevm/src/{com.oracle.svm.core/src/com/oracle/svm/core/jdk => com.oracle.svm.reflect/src/com/oracle/svm/reflect/target}/Target_jdk_internal_reflect_AccessorGenerator.java (94%) diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest index 1f18a72539227..98d8571220ae4 100644 --- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest +++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest @@ -892,6 +892,10 @@ meth public !varargs static void register(java.lang.reflect.Field[]) meth public !varargs static void registerForReflectiveInstantiation(java.lang.Class[]) supr java.lang.Object +CLSS public final org.graalvm.nativeimage.hosted.RuntimeSerialization +meth public !varargs static void register(java.lang.Class[]) +supr java.lang.Object + CLSS public abstract interface org.graalvm.nativeimage.impl.InternalPlatform innr public abstract interface static PLATFORM_JNI diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java new file mode 100644 index 0000000000000..843166d287c6b --- /dev/null +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeSerialization.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.nativeimage.hosted; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; + +@Platforms(Platform.HOSTED_ONLY.class) +public final class RuntimeSerialization { + + public static void register(Class... classes) { + ImageSingletons.lookup(RuntimeSerializationSupport.class).register(classes); + } + + private RuntimeSerialization() { + } +} diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java new file mode 100644 index 0000000000000..0158d33669cf3 --- /dev/null +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeSerializationSupport.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.nativeimage.impl; + +import java.util.Collection; + +public interface RuntimeSerializationSupport { + + void register(Class... classes); + + void register(Class clazz, Collection checkSums); + +} diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java index dfb2c343ee31b..3bb7cfb7fe110 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationSet.java @@ -106,7 +106,7 @@ public ResourceConfiguration loadResourceConfig(Function public SerializationConfiguration loadSerializationConfig(Function exceptionHandler) throws Exception { SerializationConfiguration serializationConfiguration = new SerializationConfiguration(); - loadConfig(serializationConfigPaths, new SerializationConfigurationParser((targetSerializationClass, checksums) -> serializationConfiguration.addAll(targetSerializationClass, checksums)), + loadConfig(serializationConfigPaths, new SerializationConfigurationParser<>(new SerializationConfiguration.ParseAdapter(serializationConfiguration)), exceptionHandler); return serializationConfiguration; } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java index 311c4025d0384..9fbd8d412fb1b 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfiguration.java @@ -26,60 +26,88 @@ package com.oracle.svm.configure.config; import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; import com.oracle.svm.configure.json.JsonPrintable; import com.oracle.svm.configure.json.JsonWriter; +import com.oracle.svm.core.TypeResult; +import com.oracle.svm.core.configure.SerializationConfigurationParserDelegate; +import com.oracle.svm.core.util.UserError; +import jdk.vm.ci.meta.JavaKind; public class SerializationConfiguration implements JsonPrintable { - private final ConcurrentHashMap> serializations = new ConcurrentHashMap<>(); + public static class ParseAdapter implements SerializationConfigurationParserDelegate { - public void addAll(String serializationTargetClass, Collection checksums) { - serializations.computeIfAbsent(serializationTargetClass, key -> new LinkedHashSet<>()).addAll(checksums); - } + private final SerializationConfiguration configuration; + + public ParseAdapter(SerializationConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public void registerType(SerializationConfigurationType type, List checkSums) { + configuration.add(type, checkSums); + } - public void add(String serializationTargetClass, String checksum) { - if (checksum == null) { - addAll(serializationTargetClass, Collections.emptySet()); - } else { - addAll(serializationTargetClass, Collections.singleton(checksum)); + @Override + public TypeResult resolveTypeResult(String typeName) { + SerializationConfigurationType type = configuration.get(typeName); + SerializationConfigurationType result = type != null ? type : new SerializationConfigurationType(typeName); + return TypeResult.forType(typeName, result); } } - public boolean contains(String serializationTargetClass, String checksum) { - Set checksums = serializations.get(serializationTargetClass); - return checksums != null && checksums.contains(checksum); + private final ConcurrentHashMap serializations = new ConcurrentHashMap<>(); + + public SerializationConfigurationType get(String qualifiedJavaName) { + return serializations.get(qualifiedJavaName); + } + + public void add(SerializationConfigurationType type, List checksums) { + SerializationConfigurationType previous = serializations.putIfAbsent(type.getQualifiedJavaName(), type); + UserError.guarantee(previous == null || previous == type, "Cannot replace existing type %s with %s", previous, type); + type.addCheckSums(checksums); + } + + public SerializationConfigurationType getOrCreateType(String qualifiedForNameString) { + assert qualifiedForNameString.indexOf('/') == -1 : "Requires qualified Java name, not internal representation"; + assert !qualifiedForNameString.endsWith("[]") : "Requires Class.forName syntax, for example '[Ljava.lang.String;'"; + + String s = qualifiedForNameString; + int n = 0; + while (n < s.length() && s.charAt(n) == '[') { + n++; + } + if (n > 0) { // transform to Java source syntax + StringBuilder sb = new StringBuilder(s.length() + n); + if (s.charAt(n) == 'L' && s.charAt(s.length() - 1) == ';') { + sb.append(s, n + 1, s.length() - 1); // cut off leading '[' and 'L' and trailing ';' + } else if (n == s.length() - 1) { + sb.append(JavaKind.fromPrimitiveOrVoidTypeChar(s.charAt(n)).getJavaName()); + } else { + throw new IllegalArgumentException(); + } + for (int i = 0; i < n; i++) { + sb.append("[]"); + } + s = sb.toString(); + } + return serializations.computeIfAbsent(s, SerializationConfigurationType::new); } @Override public void printJson(JsonWriter writer) throws IOException { writer.append('[').indent(); String prefix = ""; - for (Map.Entry> entry : serializations.entrySet()) { - writer.append(prefix); - writer.newline().append('{').newline(); - String className = entry.getKey(); - writer.quote("name").append(":").quote(className); - Set checksums = entry.getValue(); - if (!checksums.isEmpty()) { - writer.append(",").newline(); - writer.quote("checksum").append(':'); - if (checksums.size() == 1) { - writer.quote(checksums.iterator().next()); - } else { - writer.append(checksums.stream() - .map(JsonWriter::quoteString) - .collect(Collectors.joining(", ", "[", "]"))); - } - } - writer.newline().append('}'); + List list = new ArrayList<>(serializations.values()); + list.sort(Comparator.comparing(SerializationConfigurationType::getQualifiedJavaName)); + for (SerializationConfigurationType type : list) { + writer.append(prefix).newline(); + type.printJson(writer); prefix = ","; } writer.unindent().newline(); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java new file mode 100644 index 0000000000000..b2dcde30d2feb --- /dev/null +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/SerializationConfigurationType.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.configure.config; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import com.oracle.svm.configure.json.JsonPrintable; +import com.oracle.svm.configure.json.JsonWriter; + +public class SerializationConfigurationType implements JsonPrintable { + + private final String qualifiedJavaName; + private Set checkSums; + + public SerializationConfigurationType(String qualifiedJavaName) { + assert qualifiedJavaName.indexOf('/') == -1 : "Requires qualified Java name, not internal representation"; + assert !qualifiedJavaName.startsWith("[") : "Requires Java source array syntax, for example java.lang.String[]"; + this.qualifiedJavaName = qualifiedJavaName; + } + + public String getQualifiedJavaName() { + return qualifiedJavaName; + } + + public void addCheckSums(Collection checkSumsToAdd) { + if (checkSums == null) { + checkSums = new HashSet<>(); + } + checkSums.addAll(checkSumsToAdd); + } + + public void addCheckSum(String checkSum) { + addCheckSums(Collections.singleton(checkSum)); + } + + @Override + public void printJson(JsonWriter writer) throws IOException { + writer.append('{').indent().newline(); + writer.quote("name").append(':').quote(qualifiedJavaName); + if (checkSums != null && !checkSums.isEmpty()) { + writer.append(',').newline(); + writer.quote("checksum").append(':'); + if (checkSums.size() == 1) { + writer.quote(checkSums.iterator().next()); + } else { + writer.append(checkSums.stream() + .map(JsonWriter::quoteString) + .collect(Collectors.joining(", ", "[", "]"))); + } + } + writer.unindent().newline().append('}'); + } +} diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java index bd26ab00ee799..215afe103ef4f 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/SerializationProcessor.java @@ -51,7 +51,7 @@ void processEntry(Map entry) { List args = (List) entry.get("args"); if ("ObjectStreamClass.".equals(function)) { expectSize(args, 2); - serializationConfiguration.add((String) args.get(0), (String) args.get(1)); + serializationConfiguration.getOrCreateType((String) args.get(0)).addCheckSum((String) args.get(1)); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java index a98d3635c7feb..10a51aa74001b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java @@ -32,14 +32,15 @@ import java.util.List; import java.util.Map; +import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.util.json.JSONParser; import com.oracle.svm.core.util.json.JSONParserException; -public class SerializationConfigurationParser extends ConfigurationParser { - private final SerializationParserFunction consumer; +public class SerializationConfigurationParser extends ConfigurationParser { + private final SerializationConfigurationParserDelegate delegate; - public SerializationConfigurationParser(SerializationParserFunction consumer) { - this.consumer = consumer; + public SerializationConfigurationParser(SerializationConfigurationParserDelegate delegate) { + this.delegate = delegate; } @Override @@ -48,7 +49,7 @@ public void parseAndRegister(Reader reader) throws IOException { Object json = parser.parse(); for (Object serializationKey : asList(json, "first level of document must be an array of serialization lists")) { Map data = asMap(serializationKey, "second level of document must be serialization descriptor objects "); - String targetSerializationClass = asString(data.get("name")); + String className = asString(data.get("name")); Object checksumValue = data.get("checksum"); List checksums = new ArrayList<>(); if (checksumValue != null) { @@ -62,12 +63,18 @@ public void parseAndRegister(Reader reader) throws IOException { checksums.add(asString(jsonChecksum, "checksum")); } } - consumer.accept(targetSerializationClass, checksums); + TypeResult result = delegate.resolveTypeResult(className); + if (result.isPresent()) { + delegate.registerType(result.get(), checksums); + } else { + handleUnresolvedClass(className); + } } } - @FunctionalInterface - public interface SerializationParserFunction { - void accept(String targetSerializationClass, List checksum); + protected void handleUnresolvedClass(String className) { + throw new JSONParserException("Could not resolve " + className + " during serialization configuration." + + " The missing of this class can't be ignored even if -H:+AllowIncompleteClasspath is set." + + " Please make sure it is in the classpath"); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParserDelegate.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParserDelegate.java new file mode 100644 index 0000000000000..597cf3785054a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParserDelegate.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.configure; + +import com.oracle.svm.core.TypeResult; + +import java.util.List; + +public interface SerializationConfigurationParserDelegate { + + void registerType(T type, List checkSums); + + TypeResult resolveTypeResult(String typeName); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationDenyConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationDenyConfigurationParser.java new file mode 100644 index 0000000000000..5285aaafce5a0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationDenyConfigurationParser.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.configure; + +public class SerializationDenyConfigurationParser extends SerializationConfigurationParser> { + public SerializationDenyConfigurationParser(SerializationConfigurationParserDelegate> delegate) { + super(delegate); + } + + @Override + protected void handleUnresolvedClass(String className) { + // Checkstyle: stop + System.out.println("WARNING: Could not resolve " + className + " during serialization-deny configuration."); + // Checkstyle: resume + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/SerializationRegistryAdapter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/SerializationRegistryAdapter.java new file mode 100644 index 0000000000000..748529339aa70 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/SerializationRegistryAdapter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.config; + +import com.oracle.svm.core.TypeResult; +import com.oracle.svm.core.configure.SerializationConfigurationParserDelegate; +import com.oracle.svm.hosted.ImageClassLoader; +import jdk.vm.ci.meta.MetaUtil; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; + +import java.util.List; + +public class SerializationRegistryAdapter implements SerializationConfigurationParserDelegate> { + + private final RuntimeSerializationSupport serializationSupport; + private final ImageClassLoader classLoader; + + public SerializationRegistryAdapter(RuntimeSerializationSupport serializationSupport, ImageClassLoader classLoader) { + this.serializationSupport = serializationSupport; + this.classLoader = classLoader; + } + + @Override + public void registerType(Class type, List checkSums) { + serializationSupport.register(type, checkSums); + } + + @Override + public TypeResult> resolveTypeResult(String typeName) { + String name = typeName; + if (name.indexOf('[') != -1) { + /* accept "int[][]", "java.lang.String[]" */ + name = MetaUtil.internalNameToJava(MetaUtil.toInternalName(name), true, true); + } + return classLoader.findClass(name); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/serialize/SerializationRegistry.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationRegistry.java similarity index 97% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/serialize/SerializationRegistry.java rename to substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationRegistry.java index 82487938e327f..946ff9565d43f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/serialize/SerializationRegistry.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationRegistry.java @@ -23,7 +23,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk.serialize; +package com.oracle.svm.reflect.serialize; public interface SerializationRegistry { diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationSupport.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationSupport.java index 501d3487e54ce..997d7cd9829b3 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationSupport.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/SerializationSupport.java @@ -33,7 +33,6 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.jdk.serialize.SerializationRegistry; import com.oracle.svm.core.util.VMError; public class SerializationSupport implements SerializationRegistry { diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/SerializationFeature.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/SerializationFeature.java index a76fd32871817..413e7505eb181 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/SerializationFeature.java @@ -40,178 +40,118 @@ import java.net.URL; import java.net.URLClassLoader; import java.security.NoSuchAlgorithmException; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import com.oracle.svm.reflect.serialize.SerializationRegistry; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import org.graalvm.nativeimage.impl.RuntimeSerializationSupport; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.SerializationConfigurationParser; -import com.oracle.svm.core.configure.SerializationConfigurationParser.SerializationParserFunction; +import com.oracle.svm.core.configure.SerializationDenyConfigurationParser; import com.oracle.svm.core.jdk.Package_jdk_internal_reflect; -import com.oracle.svm.core.jdk.serialize.SerializationRegistry; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.core.util.json.JSONParserException; import com.oracle.svm.hosted.FallbackFeature; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.config.ConfigurationParserUtils; +import com.oracle.svm.hosted.config.SerializationRegistryAdapter; import com.oracle.svm.reflect.serialize.SerializationSupport; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.SerializationChecksumCalculator; -import jdk.vm.ci.meta.MetaUtil; - @AutomaticFeature public class SerializationFeature implements Feature { + private SerializationBuilder serializationBuilder; private int loadedConfigurations; @Override - public void beforeAnalysis(BeforeAnalysisAccess a) { - FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a; - SerializationBuilder serializationBuilder = new SerializationBuilder(access); - - Map, Boolean> deniedClasses = new HashMap<>(); - SerializationConfigurationParser denyCollectorParser = new SerializationConfigurationParser((strTargetSerializationClass, checksums) -> { - Class serializationTargetClass = resolveClass(strTargetSerializationClass, access); - if (serializationTargetClass != null) { - deniedClasses.put(serializationTargetClass, true); - } - }); + public void duringSetup(DuringSetupAccess a) { + FeatureImpl.DuringSetupAccessImpl access = (FeatureImpl.DuringSetupAccessImpl) a; + + SerializationDenyRegistry serializationDenyRegistry = new SerializationDenyRegistry(); + serializationBuilder = new SerializationBuilder(serializationDenyRegistry, access); + ImageSingletons.add(RuntimeSerializationSupport.class, serializationBuilder); + ImageClassLoader imageClassLoader = access.getImageClassLoader(); + SerializationDenyConfigurationParser denyCollectorParser = new SerializationDenyConfigurationParser( + new SerializationRegistryAdapter(serializationDenyRegistry, imageClassLoader)); ConfigurationParserUtils.parseAndRegisterConfigurations(denyCollectorParser, imageClassLoader, "serialization", ConfigurationFiles.Options.SerializationDenyConfigurationFiles, ConfigurationFiles.Options.SerializationDenyConfigurationResources, ConfigurationFiles.SERIALIZATION_DENY_NAME); - SerializationParserFunction serializationAdapter = (strTargetSerializationClass, checksums) -> { - Class serializationTargetClass = resolveClass(strTargetSerializationClass, access); - UserError.guarantee(serializationTargetClass != null, "Cannot find serialization target class %s. The missing of this class can't be ignored even if -H:+AllowIncompleteClasspath is set." + - " Please make sure it is in the classpath", strTargetSerializationClass); - if (Serializable.class.isAssignableFrom(serializationTargetClass)) { - if (deniedClasses.containsKey(serializationTargetClass)) { - if (deniedClasses.get(serializationTargetClass)) { - deniedClasses.put(serializationTargetClass, false); /* Warn only once */ - println("Warning: Serialization deny list contains " + serializationTargetClass.getName() + ". Image will not support serialization/deserialization of this class."); - } - } else { - Class targetConstructor = serializationBuilder.addConstructorAccessor(serializationTargetClass, checksums); - addReflections(serializationTargetClass, targetConstructor); - } - } - }; - - SerializationConfigurationParser parser = new SerializationConfigurationParser(serializationAdapter); + SerializationConfigurationParser> parser = new SerializationConfigurationParser<>(new SerializationRegistryAdapter(serializationBuilder, imageClassLoader)); loadedConfigurations = ConfigurationParserUtils.parseAndRegisterConfigurations(parser, imageClassLoader, "serialization", ConfigurationFiles.Options.SerializationConfigurationFiles, ConfigurationFiles.Options.SerializationConfigurationResources, ConfigurationFiles.SERIALIZATION_NAME); } - public static void addReflections(Class serializationTargetClass, Class targetConstructorClass) { - if (targetConstructorClass != null) { - RuntimeReflection.register(ReflectionUtil.lookupConstructor(targetConstructorClass)); - } - - if (Externalizable.class.isAssignableFrom(serializationTargetClass)) { - RuntimeReflection.register(ReflectionUtil.lookupConstructor(serializationTargetClass, (Class[]) null)); - } - - RuntimeReflection.register(serializationTargetClass); - /* - * ObjectStreamClass.computeDefaultSUID is always called at runtime to verify serialization - * class consistency, so need to register all constructors, methods and fields/ - */ - RuntimeReflection.register(serializationTargetClass.getDeclaredConstructors()); - registerMethods(serializationTargetClass); - registerFields(serializationTargetClass); + @Override + public void duringAnalysis(DuringAnalysisAccess access) { + serializationBuilder.duringAnalysis(access); } - private static void registerMethods(Class serializationTargetClass) { - RuntimeReflection.register(serializationTargetClass.getDeclaredMethods()); - // computeDefaultSUID will be reflectively called at runtime to verify class consistency - Method computeDefaultSUID = ReflectionUtil.lookupMethod(ObjectStreamClass.class, "computeDefaultSUID", Class.class); - RuntimeReflection.register(computeDefaultSUID); + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + serializationBuilder.afterAnalysis(); } - private static void registerFields(Class serializationTargetClass) { - int staticFinalMask = Modifier.STATIC | Modifier.FINAL; - int privateStaticFinalMask = Modifier.PRIVATE | staticFinalMask; - - Set serialPersistentFieldNames = new HashSet<>(); - try { - /* FIXME serialPersistentFieldNames is write-only. What is the point of this code? */ - Field f = ReflectionUtil.lookupField(serializationTargetClass, "serialPersistentFields"); - if ((f.getModifiers() & privateStaticFinalMask) == privateStaticFinalMask) { - ObjectStreamField[] serialPersistentFields = (ObjectStreamField[]) f.get(null); - for (ObjectStreamField serialPersistentField : serialPersistentFields) { - serialPersistentFieldNames.add(serialPersistentField.getName()); - } - } - } catch (ReflectionUtil.ReflectionUtilError | IllegalAccessException e) { - // No serialPersistentFields field or failed to get the field value, continue - } - - for (Field f : serializationTargetClass.getDeclaredFields()) { - int modifiers = f.getModifiers(); - boolean allowWrite = false; - boolean allowUnsafeAccess = false; - if ((modifiers & staticFinalMask) != staticFinalMask) { - allowWrite = Modifier.isFinal(f.getModifiers()); - allowUnsafeAccess = !Modifier.isStatic(f.getModifiers()); + @Override + public void beforeCompilation(BeforeCompilationAccess access) { + if (ImageSingletons.contains(FallbackFeature.class)) { + FallbackFeature.FallbackImageRequest serializationFallback = ImageSingletons.lookup(FallbackFeature.class).serializationFallback; + if (serializationFallback != null && loadedConfigurations == 0) { + throw serializationFallback; } - RuntimeReflection.register(allowWrite, allowUnsafeAccess, f); } } - private static Class resolveClass(String typeName, FeatureAccess a) { - String name = typeName; - if (name.indexOf('[') != -1) { - /* accept "int[][]", "java.lang.String[]" */ - name = MetaUtil.internalNameToJava(MetaUtil.toInternalName(name), true, true); - } - Class ret = a.findClassByName(name); - if (ret == null) { - handleError("Could not resolve " + name + " for serialization configuration."); - } - return ret; + static void println(String str) { + // Checkstyle: stop + System.out.println(str); + // Checkstyle: resume } +} + +final class SerializationDenyRegistry implements RuntimeSerializationSupport { + + private final Map, Boolean> deniedClasses = new HashMap<>(); @Override - public void beforeCompilation(BeforeCompilationAccess access) { - if (!ImageSingletons.contains(FallbackFeature.class)) { - return; - } - FallbackFeature.FallbackImageRequest serializationFallback = ImageSingletons.lookup(FallbackFeature.class).serializationFallback; - if (serializationFallback != null && loadedConfigurations == 0) { - throw serializationFallback; + public void register(Class... classes) { + for (Class clazz : classes) { + register(clazz, Collections.emptyList()); } } - private static void handleError(String message) { - boolean allowIncompleteClasspath = NativeImageOptions.AllowIncompleteClasspath.getValue(); - if (allowIncompleteClasspath) { - println("WARNING: " + message); - } else { - throw new JSONParserException(message + " To allow unresolvable reflection configuration, use option -H:+AllowIncompleteClasspath"); - } + @Override + public void register(Class clazz, Collection checkSums) { + deniedClasses.put(clazz, true); } - static void println(String str) { - // Checkstyle: stop - System.out.println(str); - // Checkstyle: resume + public boolean isAllowed(Class clazz) { + boolean denied = deniedClasses.containsKey(clazz); + if (denied && deniedClasses.get(clazz)) { + deniedClasses.put(clazz, false); /* Warn only once */ + println("WARNING: Serialization deny list contains " + clazz.getName() + ". Image will not support serialization/deserialization of this class."); + } + return !denied; } } -final class SerializationBuilder { +final class SerializationBuilder implements RuntimeSerializationSupport { /** * Using a separated classloader for serialization checksum computation to avoid initializing @@ -258,7 +198,7 @@ protected boolean isClassAbstract(Class clazz) { private final SerializationChecksumClassLoader serializationChecksumClassLoader; private final ChecksumCalculator checksumCalculator; - private final FeatureImpl.BeforeAnalysisAccessImpl access; + private final FeatureImpl.DuringSetupAccessImpl access; private final Object reflectionFactory; private final Method newConstructorForSerializationMethod; private final Method getConstructorAccessorMethod; @@ -266,8 +206,13 @@ protected boolean isClassAbstract(Class clazz) { private final Constructor stubConstructor; private final SerializationSupport serializationSupport; + private final SerializationDenyRegistry denyRegistry; + private final Map, Set> newClasses; + + private boolean sealed; + - SerializationBuilder(FeatureImpl.BeforeAnalysisAccessImpl access) { + SerializationBuilder(SerializationDenyRegistry serializationDenyRegistry, FeatureImpl.DuringSetupAccessImpl access) { try { Class reflectionFactoryClass = access.findClassByName(Package_jdk_internal_reflect.getQualifiedName() + ".ReflectionFactory"); Method getReflectionFactoryMethod = ReflectionUtil.lookupMethod(reflectionFactoryClass, "getReflectionFactory"); @@ -280,6 +225,8 @@ protected boolean isClassAbstract(Class clazz) { } stubConstructor = newConstructorForSerialization(SerializationSupport.StubForAbstractClass.class); this.access = access; + denyRegistry = serializationDenyRegistry; + newClasses = new ConcurrentHashMap<>(); URLClassLoader cl = (URLClassLoader) access.getImageClassLoader().getClassLoader(); serializationChecksumClassLoader = new SerializationChecksumClassLoader(cl.getURLs(), cl.getParent()); @@ -289,6 +236,107 @@ protected boolean isClassAbstract(Class clazz) { ImageSingletons.add(SerializationRegistry.class, serializationSupport); } + private void abortIfSealed() { + UserError.guarantee(!sealed, "Too late to add classes for serialization. Registration must happen in a Feature before the analysis has finished."); + } + + @Override + public void register(Class... classes) { + for (Class clazz : classes) { + register(clazz, Collections.emptyList()); + } + } + + @Override + public void register(Class clazz, Collection checkSums) { + abortIfSealed(); + if (!Serializable.class.isAssignableFrom(clazz)) { + println("WARNING: Could not register " + clazz.getName() + " for serialization as it does not implement Serializable."); + } else if (denyRegistry.isAllowed(clazz)) { + newClasses.compute(clazz, (k, v) -> { + Set storedCheckSums = v != null ? v : new HashSet<>(); + storedCheckSums.addAll(checkSums); + return storedCheckSums; + }); + } + } + + public void duringAnalysis(Feature.DuringAnalysisAccess a) { + if (newClasses.isEmpty()) { + return; + } + for (Map.Entry, Set> entry : newClasses.entrySet()) { + Class targetConstructor = addConstructorAccessor(entry.getKey(), entry.getValue()); + addReflections(entry.getKey(), targetConstructor); + } + newClasses.clear(); + + a.requireAnalysisIteration(); + } + + public void afterAnalysis() { + sealed = true; + if (!newClasses.isEmpty()) { + abortIfSealed(); + } + } + + private static void addReflections(Class serializationTargetClass, Class targetConstructorClass) { + if (targetConstructorClass != null) { + RuntimeReflection.register(ReflectionUtil.lookupConstructor(targetConstructorClass)); + } + + if (Externalizable.class.isAssignableFrom(serializationTargetClass)) { + RuntimeReflection.register(ReflectionUtil.lookupConstructor(serializationTargetClass, (Class[]) null)); + } + + RuntimeReflection.register(serializationTargetClass); + /* + * ObjectStreamClass.computeDefaultSUID is always called at runtime to verify serialization + * class consistency, so need to register all constructors, methods and fields/ + */ + RuntimeReflection.register(serializationTargetClass.getDeclaredConstructors()); + registerMethods(serializationTargetClass); + registerFields(serializationTargetClass); + } + + private static void registerMethods(Class serializationTargetClass) { + RuntimeReflection.register(serializationTargetClass.getDeclaredMethods()); + // computeDefaultSUID will be reflectively called at runtime to verify class consistency + Method computeDefaultSUID = ReflectionUtil.lookupMethod(ObjectStreamClass.class, "computeDefaultSUID", Class.class); + RuntimeReflection.register(computeDefaultSUID); + } + + private static void registerFields(Class serializationTargetClass) { + int staticFinalMask = Modifier.STATIC | Modifier.FINAL; + int privateStaticFinalMask = Modifier.PRIVATE | staticFinalMask; + + Set serialPersistentFieldNames = new HashSet<>(); + try { + /* FIXME serialPersistentFieldNames is write-only. What is the point of this code? */ + Field f = ReflectionUtil.lookupField(serializationTargetClass, "serialPersistentFields"); + if ((f.getModifiers() & privateStaticFinalMask) == privateStaticFinalMask) { + ObjectStreamField[] serialPersistentFields = (ObjectStreamField[]) f.get(null); + for (ObjectStreamField serialPersistentField : serialPersistentFields) { + serialPersistentFieldNames.add(serialPersistentField.getName()); + } + } + } catch (ReflectionUtil.ReflectionUtilError | IllegalAccessException e) { + // No serialPersistentFields field or failed to get the field value, continue + } + + for (Field f : serializationTargetClass.getDeclaredFields()) { + int modifiers = f.getModifiers(); + boolean allowWrite = false; + boolean allowUnsafeAccess = false; + if ((modifiers & staticFinalMask) != staticFinalMask) { + allowWrite = Modifier.isFinal(f.getModifiers()); + allowUnsafeAccess = !Modifier.isStatic(f.getModifiers()); + } + RuntimeReflection.register(allowWrite, allowUnsafeAccess, f); + } + } + private Constructor newConstructorForSerialization(Class serializationTargetClass) { try { return (Constructor) newConstructorForSerializationMethod.invoke(reflectionFactory, serializationTargetClass); @@ -313,7 +361,7 @@ private Constructor getExternalizableConstructor(Class serializationTarget } } - Class addConstructorAccessor(Class serializationTargetClass, List configuredChecksums) { + private Class addConstructorAccessor(Class serializationTargetClass, Collection configuredChecksums) { if (serializationTargetClass.isArray() || Enum.class.isAssignableFrom(serializationTargetClass)) { return null; } @@ -347,7 +395,7 @@ Class addConstructorAccessor(Class serializationTargetClass, List return targetConstructorClass; } - private void verifyBuildTimeChecksum(Class serializationTargetClass, Class targetConstructorClass, List configuredChecksums) { + private void verifyBuildTimeChecksum(Class serializationTargetClass, Class targetConstructorClass, Collection configuredChecksums) { if (configuredChecksums.isEmpty()) { return; } diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/package-info.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/package-info.java new file mode 100644 index 0000000000000..9d86e8244014f --- /dev/null +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/serialize/hosted/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +@Platforms(Platform.HOSTED_ONLY.class) +package com.oracle.svm.reflect.serialize.hosted; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_AccessorGenerator.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_jdk_internal_reflect_AccessorGenerator.java similarity index 94% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_AccessorGenerator.java rename to substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_jdk_internal_reflect_AccessorGenerator.java index 0640148db7a8c..18bb76bd79351 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_AccessorGenerator.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/target/Target_jdk_internal_reflect_AccessorGenerator.java @@ -22,13 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.core.jdk; +package com.oracle.svm.reflect.target; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.jdk.serialize.SerializationRegistry; +import com.oracle.svm.core.jdk.Package_jdk_internal_reflect; +import com.oracle.svm.reflect.serialize.SerializationRegistry; @TargetClass(classNameProvider = Package_jdk_internal_reflect.class, className = "AccessorGenerator") public final class Target_jdk_internal_reflect_AccessorGenerator {