Skip to content
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

Initial native image agent with JVM mode tests integration #36826

Merged
merged 7 commits into from
Jun 3, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Enable option to run integration tests with native image agent
* Added a build step to generate native image agent filters.
These limit the generated configuration to avoid some of
configuration that Quarkus already takes care of.
* Native image agent goal added to Quarkus maven plugin
to post-process native image agent configuration files.
In particular, the native image agent filters do not
impact resource configuration, so these files are
post-processed to remove configuration that Quarkus takes care of.
* Added a JSON parser to read the resources configuration
that the native image agent generates.
* Added the ability to transform JSON, which links the
JSON parser and JSON emitter.
* Added native agent integration test.
* The integration tests that run with native image agent
execute Quarkus JVM mode using the `java` within the Mandrel
builder image.
* Refactored container code to enable container launcher
to share container runtime parameters common to other similar
use cases. In particular, volume related options need to be
carefully constructed.
galderz committed May 22, 2024
commit 7493ab4ab24c7277067a0755354bb634bcdd5b5d
148 changes: 128 additions & 20 deletions core/builder/src/main/java/io/quarkus/builder/Json.java
Original file line number Diff line number Diff line change
@@ -11,6 +11,15 @@
import java.util.Map.Entry;
import java.util.Objects;

import io.quarkus.builder.json.JsonArray;
import io.quarkus.builder.json.JsonBoolean;
import io.quarkus.builder.json.JsonInteger;
import io.quarkus.builder.json.JsonMember;
import io.quarkus.builder.json.JsonMultiValue;
import io.quarkus.builder.json.JsonObject;
import io.quarkus.builder.json.JsonString;
import io.quarkus.builder.json.JsonValue;

/**
* A simple JSON string generator.
*/
@@ -48,44 +57,54 @@ private Json() {
* @return the new JSON array builder, empty builders are not ignored
*/
public static JsonArrayBuilder array() {
return new JsonArrayBuilder(false);
return new JsonArrayBuilder(false, false);
}

/**
* @param ignoreEmptyBuilders
* @return the new JSON array builder
* @see JsonBuilder#ignoreEmptyBuilders
*/
static JsonArrayBuilder array(boolean ignoreEmptyBuilders) {
return new JsonArrayBuilder(ignoreEmptyBuilders);
public static JsonArrayBuilder array(boolean ignoreEmptyBuilders, boolean skipEscapeCharacters) {
return new JsonArrayBuilder(ignoreEmptyBuilders, skipEscapeCharacters);
}

/**
* @return the new JSON object builder, empty builders are not ignored
*/
public static JsonObjectBuilder object() {
return new JsonObjectBuilder(false);
return new JsonObjectBuilder(false, false);
}

/**
* @param ignoreEmptyBuilders
* @return the new JSON object builder
* @see JsonBuilder#ignoreEmptyBuilders
*/
static JsonObjectBuilder object(boolean ignoreEmptyBuilders) {
return new JsonObjectBuilder(ignoreEmptyBuilders);
public static JsonObjectBuilder object(boolean ignoreEmptyBuilders, boolean skipEscapeCharacters) {
return new JsonObjectBuilder(ignoreEmptyBuilders, skipEscapeCharacters);
}

abstract static class JsonBuilder<T> {
public abstract static class JsonBuilder<T> {

protected boolean ignoreEmptyBuilders = false;
protected final boolean ignoreEmptyBuilders;
/**
* Skips escaping characters in string values.
* This option should be enabled when transforming JSON input,
* whose string values are already escaped.
* In situations like this, the option avoids escaping characters
* that are already escaped.
*/
protected final boolean skipEscapeCharacters;
protected JsonTransform transform;

/**
* @param ignoreEmptyBuilders If set to true all empty builders added to this builder will be ignored during
* {@link #build()}
*/
JsonBuilder(boolean ignoreEmptyBuilders) {
JsonBuilder(boolean ignoreEmptyBuilders, boolean skipEscapeCharacters) {
this.ignoreEmptyBuilders = ignoreEmptyBuilders;
this.skipEscapeCharacters = skipEscapeCharacters;
}

/**
@@ -130,6 +149,16 @@ protected boolean isValuesEmpty(Collection<Object> values) {

protected abstract T self();

abstract void add(JsonValue element);

void setTransform(JsonTransform transform) {
this.transform = transform;
}

public void transform(JsonMultiValue value, JsonTransform transform) {
final ResolvedTransform resolved = new ResolvedTransform(this, transform);
value.forEach(resolved);
}
}

/**
@@ -139,8 +168,8 @@ public static class JsonArrayBuilder extends JsonBuilder<JsonArrayBuilder> {

private final List<Object> values;

private JsonArrayBuilder(boolean ignoreEmptyBuilders) {
super(ignoreEmptyBuilders);
private JsonArrayBuilder(boolean ignoreEmptyBuilders, boolean skipEscapeCharacters) {
super(ignoreEmptyBuilders, skipEscapeCharacters);
this.values = new ArrayList<Object>();
}

@@ -209,7 +238,7 @@ public void appendTo(Appendable appendable) throws IOException {
if (++idx > 1) {
appendable.append(ENTRY_SEPARATOR);
}
appendValue(appendable, value);
appendValue(appendable, value, skipEscapeCharacters);
}
appendable.append(ARRAY_END);
}
@@ -219,6 +248,32 @@ protected JsonArrayBuilder self() {
return this;
}

@Override
void add(JsonValue element) {
if (element instanceof JsonString) {
add(((JsonString) element).value());
} else if (element instanceof JsonInteger) {
final long longValue = ((JsonInteger) element).longValue();
final int intValue = (int) longValue;
if (longValue == intValue) {
add(intValue);
} else {
add(longValue);
}
} else if (element instanceof JsonBoolean) {
add(((JsonBoolean) element).value());
} else if (element instanceof JsonArray) {
final JsonArrayBuilder arrayBuilder = Json.array(ignoreEmptyBuilders, skipEscapeCharacters);
arrayBuilder.transform((JsonArray) element, transform);
add(arrayBuilder);
} else if (element instanceof JsonObject) {
final JsonObjectBuilder objectBuilder = Json.object(ignoreEmptyBuilders, skipEscapeCharacters);
objectBuilder.transform((JsonObject) element, transform);
if (!objectBuilder.isEmpty()) {
add(objectBuilder);
}
}
}
}

/**
@@ -228,8 +283,8 @@ public static class JsonObjectBuilder extends JsonBuilder<JsonObjectBuilder> {

private final Map<String, Object> properties;

private JsonObjectBuilder(boolean ignoreEmptyBuilders) {
super(ignoreEmptyBuilders);
private JsonObjectBuilder(boolean ignoreEmptyBuilders, boolean skipEscapeCharacters) {
super(ignoreEmptyBuilders, skipEscapeCharacters);
this.properties = new HashMap<String, Object>();
}

@@ -299,9 +354,9 @@ public void appendTo(Appendable appendable) throws IOException {
if (++idx > 1) {
appendable.append(ENTRY_SEPARATOR);
}
appendStringValue(appendable, entry.getKey());
appendStringValue(appendable, entry.getKey(), skipEscapeCharacters);
appendable.append(NAME_VAL_SEPARATOR);
appendValue(appendable, entry.getValue());
appendValue(appendable, entry.getValue(), skipEscapeCharacters);
}
appendable.append(OBJECT_END);
}
@@ -311,25 +366,61 @@ protected JsonObjectBuilder self() {
return this;
}

@Override
void add(JsonValue element) {
if (element instanceof JsonMember) {
final JsonMember member = (JsonMember) element;
final String attribute = member.attribute().value();
final JsonValue value = member.value();
if (value instanceof JsonString) {
put(attribute, ((JsonString) value).value());
} else if (value instanceof JsonInteger) {
final long longValue = ((JsonInteger) value).longValue();
final int intValue = (int) longValue;
if (longValue == intValue) {
put(attribute, intValue);
} else {
put(attribute, longValue);
}
} else if (value instanceof JsonBoolean) {
final boolean booleanValue = ((JsonBoolean) value).value();
put(attribute, booleanValue);
} else if (value instanceof JsonArray) {
final JsonArrayBuilder arrayBuilder = Json.array(ignoreEmptyBuilders, skipEscapeCharacters);
arrayBuilder.transform((JsonArray) value, transform);
put(attribute, arrayBuilder);
} else if (value instanceof JsonObject) {
final JsonObjectBuilder objectBuilder = Json.object(ignoreEmptyBuilders, skipEscapeCharacters);
objectBuilder.transform((JsonObject) value, transform);
if (!objectBuilder.isEmpty()) {
put(attribute, objectBuilder);
}
}
}
}
}

static void appendValue(Appendable appendable, Object value) throws IOException {
static void appendValue(Appendable appendable, Object value, boolean skipEscapeCharacters) throws IOException {
if (value instanceof JsonObjectBuilder) {
appendable.append(((JsonObjectBuilder) value).build());
} else if (value instanceof JsonArrayBuilder) {
appendable.append(((JsonArrayBuilder) value).build());
} else if (value instanceof String) {
appendStringValue(appendable, value.toString());
appendStringValue(appendable, value.toString(), skipEscapeCharacters);
} else if (value instanceof Boolean || value instanceof Integer || value instanceof Long) {
appendable.append(value.toString());
} else {
throw new IllegalStateException("Unsupported value type: " + value);
}
}

static void appendStringValue(Appendable appendable, String value) throws IOException {
static void appendStringValue(Appendable appendable, String value, boolean skipEscapeCharacters) throws IOException {
appendable.append(CHAR_QUOTATION_MARK);
appendable.append(escape(value));
if (skipEscapeCharacters) {
appendable.append(value);
} else {
appendable.append(escape(value));
}
appendable.append(CHAR_QUOTATION_MARK);
}

@@ -354,4 +445,21 @@ static String escape(String value) {
return builder.toString();
}

private static final class ResolvedTransform implements JsonTransform {
private final Json.JsonBuilder<?> resolvedBuilder;
private final JsonTransform transform;

private ResolvedTransform(Json.JsonBuilder<?> resolvedBuilder, JsonTransform transform) {
this.resolvedBuilder = resolvedBuilder;
this.resolvedBuilder.setTransform(transform);
zakkak marked this conversation as resolved.
Show resolved Hide resolved
this.transform = transform;
}

@Override
public void accept(Json.JsonBuilder<?> builder, JsonValue element) {
if (builder == null) {
transform.accept(resolvedBuilder, element);
}
}
}
}
Loading