Harmonize the use of Writer rather than Generator

This commit is contained in:
Stephane Nicoll
2022-04-11 16:17:42 +02:00
parent 4e9306fa1b
commit f65136dd68
13 changed files with 236 additions and 235 deletions

View File

@@ -1,136 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aot.nativex;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import org.springframework.aot.hint.JavaSerializationHints;
import org.springframework.aot.hint.ProxyHints;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.ResourceHints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.lang.Nullable;
/**
* Generate the GraalVM native configuration files from runtime hints.
*
* @author Sebastien Deleuze
* @since 6.0
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
public class FileNativeConfigurationGenerator implements NativeConfigurationGenerator {
private final Path basePath;
private final String groupId;
private final String artifactId;
public FileNativeConfigurationGenerator(Path basePath) {
this(basePath, null, null);
}
public FileNativeConfigurationGenerator(Path basePath, @Nullable String groupId, @Nullable String artifactId) {
this.basePath = basePath;
if ((groupId == null && artifactId != null) || (groupId != null && artifactId == null)) {
throw new IllegalArgumentException("groupId and artifactId must be both null or both non-null");
}
this.groupId = groupId;
this.artifactId = artifactId;
}
@Override
public void generate(RuntimeHints hints) {
try {
if (hints.javaSerialization().types().findAny().isPresent()) {
generateFile(hints.javaSerialization());
}
if (hints.proxies().jdkProxies().findAny().isPresent()) {
generateFile(hints.proxies());
}
if (hints.reflection().typeHints().findAny().isPresent()) {
generateFile(hints.reflection());
}
if (hints.resources().resourcePatterns().findAny().isPresent() ||
hints.resources().resourceBundles().findAny().isPresent()) {
generateFile(hints.resources());
}
}
catch (IOException ex) {
throw new IllegalStateException("Unexpected I/O error while writing the native configuration", ex);
}
}
/**
* Generate the Java serialization native configuration file.
*/
private void generateFile(JavaSerializationHints hints) throws IOException {
JavaSerializationHintsSerializer serializer = new JavaSerializationHintsSerializer();
File file = createIfNecessary("serialization-config.json");
FileWriter writer = new FileWriter(file);
writer.write(serializer.serialize(hints));
writer.close();
}
/**
* Generate the proxy native configuration file.
*/
private void generateFile(ProxyHints hints) throws IOException {
ProxyHintsSerializer serializer = new ProxyHintsSerializer();
File file = createIfNecessary("proxy-config.json");
FileWriter writer = new FileWriter(file);
writer.write(serializer.serialize(hints));
writer.close();
}
/**
* Generate the reflection native configuration file.
*/
private void generateFile(ReflectionHints hints) throws IOException {
ReflectionHintsSerializer serializer = new ReflectionHintsSerializer();
File file = createIfNecessary("reflect-config.json");
FileWriter writer = new FileWriter(file);
writer.write(serializer.serialize(hints));
writer.close();
}
/**
* Generate the resource native configuration file.
*/
private void generateFile(ResourceHints hints) throws IOException {
ResourceHintsSerializer serializer = new ResourceHintsSerializer();
File file = createIfNecessary("resource-config.json");
FileWriter writer = new FileWriter(file);
writer.write(serializer.serialize(hints));
writer.close();
}
private File createIfNecessary(String filename) throws IOException {
Path outputDirectory = this.basePath.resolve("META-INF").resolve("native-image");
if (this.groupId != null && this.artifactId != null) {
outputDirectory = outputDirectory.resolve(this.groupId).resolve(this.artifactId);
}
outputDirectory.toFile().mkdirs();
File file = outputDirectory.resolve(filename).toFile();
file.createNewFile();
return file;
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aot.nativex;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Path;
import java.util.function.Consumer;
import org.springframework.lang.Nullable;
/**
* A {@link NativeConfigurationWriter} implementation that writes the
* configuration to disk.
*
* @author Sebastien Deleuze
* @author Stephane Nicoll
* @since 6.0
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
public class FileNativeConfigurationWriter extends NativeConfigurationWriter {
private final Path basePath;
private final String groupId;
private final String artifactId;
public FileNativeConfigurationWriter(Path basePath) {
this(basePath, null, null);
}
public FileNativeConfigurationWriter(Path basePath, @Nullable String groupId, @Nullable String artifactId) {
this.basePath = basePath;
if ((groupId == null && artifactId != null) || (groupId != null && artifactId == null)) {
throw new IllegalArgumentException("groupId and artifactId must be both null or both non-null");
}
this.groupId = groupId;
this.artifactId = artifactId;
}
@Override
protected void writeTo(String fileName, Consumer<BasicJsonWriter> writer) {
try {
File file = createIfNecessary(fileName);
try (FileWriter out = new FileWriter(file)) {
writer.accept(createJsonWriter(out));
}
}
catch (IOException ex) {
throw new IllegalStateException("Failed to write native configuration for " + fileName, ex);
}
}
private File createIfNecessary(String filename) throws IOException {
Path outputDirectory = this.basePath.resolve("META-INF").resolve("native-image");
if (this.groupId != null && this.artifactId != null) {
outputDirectory = outputDirectory.resolve(this.groupId).resolve(this.artifactId);
}
outputDirectory.toFile().mkdirs();
File file = outputDirectory.resolve(filename).toFile();
file.createNewFile();
return file;
}
private BasicJsonWriter createJsonWriter(Writer out) {
return new BasicJsonWriter(out);
}
}

View File

@@ -16,7 +16,6 @@
package org.springframework.aot.nativex;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -24,7 +23,7 @@ import org.springframework.aot.hint.JavaSerializationHints;
import org.springframework.aot.hint.TypeReference;
/**
* Serialize a {@link JavaSerializationHints} to the JSON output expected by the
* Write a {@link JavaSerializationHints} to the JSON output expected by the
* GraalVM {@code native-image} compiler, typically named
* {@code serialization-config.json}.
*
@@ -33,13 +32,12 @@ import org.springframework.aot.hint.TypeReference;
* @since 6.0
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
class JavaSerializationHintsSerializer {
class JavaSerializationHintsWriter {
public String serialize(JavaSerializationHints hints) {
StringWriter sw = new StringWriter();
BasicJsonWriter writer = new BasicJsonWriter(sw, " ");
public static final JavaSerializationHintsWriter INSTANCE = new JavaSerializationHintsWriter();
public void write(BasicJsonWriter writer, JavaSerializationHints hints) {
writer.writeArray(hints.types().map(this::toAttributes).toList());
return sw.toString();
}
private Map<String, Object> toAttributes(TypeReference typeReference) {

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aot.nativex;
import org.springframework.aot.hint.RuntimeHints;
/**
* Generate GraalVM native configuration.
*
* @author Sebastien Deleuze
* @since 6.0
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
public interface NativeConfigurationGenerator {
/**
* Generate the GraalVM native configuration from the provided hints.
* @param hints the hints to serialize
*/
void generate(RuntimeHints hints);
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aot.nativex;
import java.util.function.Consumer;
import org.springframework.aot.hint.JavaSerializationHints;
import org.springframework.aot.hint.ProxyHints;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.ResourceHints;
import org.springframework.aot.hint.RuntimeHints;
/**
* Write {@link RuntimeHints} as GraalVM native configuration.
*
* @author Sebastien Deleuze
* @author Stephane Nicoll
* @since 6.0
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
public abstract class NativeConfigurationWriter {
/**
* Write the GraalVM native configuration from the provided hints.
* @param hints the hints to handle
*/
public void write(RuntimeHints hints) {
if (hints.javaSerialization().types().findAny().isPresent()) {
writeJavaSerializationHints(hints.javaSerialization());
}
if (hints.proxies().jdkProxies().findAny().isPresent()) {
writeProxyHints(hints.proxies());
}
if (hints.reflection().typeHints().findAny().isPresent()) {
writeReflectionHints(hints.reflection());
}
if (hints.resources().resourcePatterns().findAny().isPresent() ||
hints.resources().resourceBundles().findAny().isPresent()) {
writeResourceHints(hints.resources());
}
}
/**
* Write the specified GraalVM native configuration file, using the
* provided {@link BasicJsonWriter}.
* @param fileName the name of the file
* @param writer a consumer for the writer to use
*/
protected abstract void writeTo(String fileName, Consumer<BasicJsonWriter> writer);
private void writeJavaSerializationHints(JavaSerializationHints hints) {
writeTo("serialization-config.json", writer ->
JavaSerializationHintsWriter.INSTANCE.write(writer, hints));
}
private void writeProxyHints(ProxyHints hints) {
writeTo("proxy-config.json", writer ->
ProxyHintsWriter.INSTANCE.write(writer, hints));
}
private void writeReflectionHints(ReflectionHints hints) {
writeTo("reflect-config.json", writer ->
ReflectionHintsWriter.INSTANCE.write(writer, hints));
}
private void writeResourceHints(ResourceHints hints) {
writeTo("resource-config.json", writer ->
ResourceHintsWriter.INSTANCE.write(writer, hints));
}
}

View File

@@ -16,7 +16,6 @@
package org.springframework.aot.nativex;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -25,7 +24,7 @@ import org.springframework.aot.hint.ProxyHints;
import org.springframework.aot.hint.TypeReference;
/**
* Serialize {@link JdkProxyHint}s contained in a {@link ProxyHints} to the JSON
* Write {@link JdkProxyHint}s contained in a {@link ProxyHints} to the JSON
* output expected by the GraalVM {@code native-image} compiler, typically named
* {@code proxy-config.json}.
*
@@ -35,13 +34,12 @@ import org.springframework.aot.hint.TypeReference;
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/DynamicProxy/">Dynamic Proxy in Native Image</a>
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
class ProxyHintsSerializer {
class ProxyHintsWriter {
public String serialize(ProxyHints hints) {
StringWriter sw = new StringWriter();
BasicJsonWriter writer = new BasicJsonWriter(sw, " ");
public static final ProxyHintsWriter INSTANCE = new ProxyHintsWriter();
public void write(BasicJsonWriter writer, ProxyHints hints) {
writer.writeArray(hints.jdkProxies().map(this::toAttributes).toList());
return sw.toString();
}
private Map<String, Object> toAttributes(JdkProxyHint hint) {

View File

@@ -16,7 +16,6 @@
package org.springframework.aot.nativex;
import java.io.StringWriter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
@@ -34,7 +33,7 @@ import org.springframework.aot.hint.TypeReference;
import org.springframework.lang.Nullable;
/**
* Serialize {@link ReflectionHints} to the JSON output expected by the GraalV
* Write {@link ReflectionHints} to the JSON output expected by the GraalVM
* {@code native-image} compiler, typically named {@code reflect-config.json}.
*
* @author Sebastien Deleuze
@@ -43,13 +42,12 @@ import org.springframework.lang.Nullable;
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/Reflection/">Reflection Use in Native Images</a>
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
class ReflectionHintsSerializer {
class ReflectionHintsWriter {
public String serialize(ReflectionHints hints) {
StringWriter sw = new StringWriter();
BasicJsonWriter writer = new BasicJsonWriter(sw, " ");
public static final ReflectionHintsWriter INSTANCE = new ReflectionHintsWriter();
public void write(BasicJsonWriter writer, ReflectionHints hints) {
writer.writeArray(hints.typeHints().map(this::toAttributes).toList());
return sw.toString();
}
private Map<String, Object> toAttributes(TypeHint hint) {

View File

@@ -16,7 +16,6 @@
package org.springframework.aot.nativex;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -32,7 +31,7 @@ import org.springframework.aot.hint.ResourcePatternHint;
import org.springframework.lang.Nullable;
/**
* Serialize a {@link ResourceHints} to the JSON output expected by the GraalVM
* Write a {@link ResourceHints} to the JSON output expected by the GraalVM
* {@code native-image} compiler, typically named {@code resource-config.json}.
*
* @author Sebastien Deleuze
@@ -41,16 +40,15 @@ import org.springframework.lang.Nullable;
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/Resources/">Accessing Resources in Native Images</a>
* @see <a href="https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/">Native Image Build Configuration</a>
*/
class ResourceHintsSerializer {
class ResourceHintsWriter {
public String serialize(ResourceHints hints) {
StringWriter out = new StringWriter();
BasicJsonWriter writer = new BasicJsonWriter(out, "\t");
public static final ResourceHintsWriter INSTANCE = new ResourceHintsWriter();
public void write(BasicJsonWriter writer, ResourceHints hints) {
Map<String, Object> attributes = new LinkedHashMap<>();
attributes.put("resources", toAttributes(hints));
handleResourceBundles(attributes, hints.resourceBundles());
writer.writeObject(attributes);
return out.toString();
}
private Map<String, Object> toAttributes(ResourceHints hint) {