Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ private Stream<Bean> findAllBeans(final RoundEnvironment roundEnv, final Set<? e
}

if (it instanceof ExecutableElement ee) {
if (ee.getParameters().size() == 0) {
if (ee.getParameters().isEmpty()) {
processingEnv.getMessager().printMessage(ERROR, "Unsupported listener, should get exactly at least one parameter: '" + it.getEnclosingElement() + "." + it + "'");
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,23 @@ public BaseHttpEndpointGenerator.Generation get() {
.filter(it -> !"context.request()".equals(it.invocation()))
.map(it -> {
final var meta = jsonRpcParams.get(counter.getAndIncrement());
final var paramElement = method.getParameters().get(counter.get() - 1);
final var jsonRpcParam = ofNullable(paramElement.getAnnotation(JsonRpcParam.class));
final var required = jsonRpcParam.map(JsonRpcParam::required).filter(b -> b).orElse(null);
return new PartialOpenRPC.Value(
meta.name(),
null, null, null,
getSchema(meta.type()));
jsonRpcParam.map(JsonRpcParam::documentation).filter(Predicate.not(String::isBlank)).orElse(null),
required,
paramElement.getAnnotation(Deprecated.class) != null ? true : null,
getSchema(meta.type(), required));
})
.toList(),
new PartialOpenRPC.Value(
"result",
null, null, null,
isVoid ?
new JsonSchema(null, null, "null", true, null, null, null, null, null) :
getSchema(new EnrichedParsedType(returnType))),
getSchema(new EnrichedParsedType(returnType), null)),
Stream.of(endpoint.errors())
.map(it -> new PartialOpenRPC.ErrorValue(it.code(), it.documentation(), null))
.toList()));
Expand Down Expand Up @@ -247,34 +252,33 @@ private JsonSchema toSchema(final Map<String, Object> read) {
ofNullable(read.get("items")).map(Map.class::cast).map(it -> toSchema((Map<String, Object>) it)).orElse(null),
ofNullable(read.get("title")).map(String::valueOf).orElse(null),
ofNullable(read.get("description")).map(String::valueOf).orElse(null),
ofNullable(read.get("enum")).map(List.class::cast).orElse(null));
ofNullable(read.get("enum")).map(List.class::cast).orElse(null),
ofNullable(read.get("required")).map(List.class::cast).orElse(null));
}

private JsonSchema getSchema(final EnrichedParsedType enrichedParsedType) {
private JsonSchema getSchema(final EnrichedParsedType enrichedParsedType, final Boolean required) {
final var type = enrichedParsedType.type();
switch (type.type()) {
case CLASS -> {
return switch (type.className()) {
case "java.lang.Object" -> new JsonSchema(null, null, "object", true, null, null, true, null, null);
case "java.lang.Object" -> new JsonSchema(null, null, "object", !(required != null && required), null, null, true, null, null);
case "boolean", "java.lang.Boolean" ->
new JsonSchema(null, null, "boolean", !"boolean".equals(type.className()), null, null, null, null, null);
new JsonSchema(null, null, "boolean", !(required != null && required) && !"boolean".equals(type.className()), null, null, null, null, null);
case "int", "java.lang.Integer" ->
new JsonSchema(null, null, "integer", !"int".equals(type.className()), "int32", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"int".equals(type.className()), "int32", null, null, null, null);
case "long", "java.lang.Long" ->
new JsonSchema(null, null, "integer", !"long".equals(type.className()), "int64", null, null, null, null);
case "java.time.OffsetDateTime" ->
new JsonSchema(null, null, "string", true, "date-time", null, null, null, null);
case "java.time.ZoneOffset" ->
new JsonSchema(null, null, "string", true, "date-time", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"long".equals(type.className()), "int64", null, null, null, null);
case "java.time.OffsetDateTime", "java.time.ZoneOffset" ->
new JsonSchema(null, null, "string", !(required != null && required), "date-time", null, null, null, null);
case "java.time.LocalDate" ->
new JsonSchema(null, null, "string", true, "date", null, null, null, null);
case "java.lang.String" -> new JsonSchema(null, null, "string", true, null, null, null, null, null);
new JsonSchema(null, null, "string", !(required != null && required), "date", null, null, null, null);
case "java.lang.String" -> new JsonSchema(null, null, "string", !(required != null && required), null, null, null, null, null);
default -> {
if (type.enumValues() != null) {
yield new JsonSchema(
null, null,
"string",
null, null, null, null, null, null, null, null,
required != null && required ? false : null, null, null, null, null, null, null, null,
type.enumValues());
}
final var schema = openRPC.schemas().computeIfAbsent(
Expand All @@ -283,7 +287,7 @@ yield new JsonSchema(
final var id = schema.id() == null ? schema.ref() : schema.id();
yield new JsonSchema(
"#/schemas/" + requireNonNull(id, "missing id/ref: " + id),
null, null, null, null, null, null, null, null);
null, null, (required != null && required) ? false : null, null, null, null, null, null);
}
};
}
Expand All @@ -292,45 +296,45 @@ yield new JsonSchema(
case "java.util.Collection", "java.util.List", "java.util.Set" -> {
return new JsonSchema(
null, null,
"array", true,
"array", !(required != null && required),
null, null,
null, null,
switch (type.args().get(0)) {
case "java.lang.Object" ->
new JsonSchema(null, null, "object", true, null, null, true, null, null);
new JsonSchema(null, null, "object", !(required != null && required), null, null, true, null, null);
case "boolean", "java.lang.Boolean" ->
new JsonSchema(null, null, "boolean", !"boolean".equals(type.args().get(0)), null, null, null, null, null);
new JsonSchema(null, null, "boolean", !(required != null && required) && !"boolean".equals(type.args().get(0)), null, null, null, null, null);
case "int", "java.lang.Integer" ->
new JsonSchema(null, null, "integer", !"int".equals(type.args().get(0)), "int32", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"int".equals(type.args().get(0)), "int32", null, null, null, null);
case "long", "java.lang.Long" ->
new JsonSchema(null, null, "integer", !"long".equals(type.args().get(0)), "int64", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"long".equals(type.args().get(0)), "int64", null, null, null, null);
case "java.lang.String" ->
new JsonSchema(null, null, "string", true, null, null, null, null, null);
new JsonSchema(null, null, "string", !(required != null && required), null, null, null, null, null);
default -> {
final var schema = openRPC.schemas().computeIfAbsent(
type.args().get(0).replace('$', '.'),
k -> generateFullJsonSchema(type.args().get(0)));
final var id = schema.id() == null ? schema.ref() : schema.id();
yield new JsonSchema(
"#/schemas/" + requireNonNull(id, "missing id/ref: " + schema),
null, null, null, null, null, null, null, null);
null, null, (required != null && required) ? false : null, null, null, null, null, null);
}
});
}
case "java.util.Map" -> {
return new JsonSchema(
null, null,
"object", true,
"object", !(required != null && required),
null, null,
(switch (type.args().get(1)) {
case "java.lang.Object" ->
new JsonSchema(null, null, "object", true, null, null, true, null, null);
new JsonSchema(null, null, "object", !(required != null && required), null, null, true, null, null);
case "boolean", "java.lang.Boolean" ->
new JsonSchema(null, null, "boolean", !"boolean".equals(type.args().get(1)), null, null, null, null, null);
new JsonSchema(null, null, "boolean", !(required != null && required) && !"boolean".equals(type.args().get(1)), null, null, null, null, null);
case "int", "java.lang.Integer" ->
new JsonSchema(null, null, "integer", !"int".equals(type.args().get(1)), "int32", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"int".equals(type.args().get(1)), "int32", null, null, null, null);
case "long", "java.lang.Long" ->
new JsonSchema(null, null, "integer", !"long".equals(type.args().get(1)), "int64", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"long".equals(type.args().get(1)), "int64", null, null, null, null);
case "java.lang.String" ->
new JsonSchema(null, null, "string", true, null, null, null, null, null);
default -> {
Expand All @@ -340,35 +344,35 @@ yield new JsonSchema(
final var id = schema.id() == null ? schema.ref() : schema.id();
yield new JsonSchema(
"#/schemas/" + requireNonNull(id, "missing id/ref: " + schema),
null, null, null, null, null, null, null, null);
null, null, (required != null && required) ? false : null, null, null, null, null, null);
}
}).asMap(),
null, null);
}
case "java.util.Optional", "java.util.concurrent.CompletionStage" -> {
return new JsonSchema(
null, null,
"object", true,
"object", !(required != null && required),
null, null,
(switch (type.args().get(0)) {
case "java.lang.Object" ->
new JsonSchema(null, null, "object", true, null, null, true, null, null);
new JsonSchema(null, null, "object", !(required != null && required), null, null, true, null, null);
case "boolean", "java.lang.Boolean" ->
new JsonSchema(null, null, "boolean", !"boolean".equals(type.args().get(0)), null, null, null, null, null);
new JsonSchema(null, null, "boolean", !(required != null && required) && !"boolean".equals(type.args().get(0)), null, null, null, null, null);
case "int", "java.lang.Integer" ->
new JsonSchema(null, null, "integer", !"int".equals(type.args().get(0)), "int32", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"int".equals(type.args().get(0)), "int32", null, null, null, null);
case "long", "java.lang.Long" ->
new JsonSchema(null, null, "integer", !"long".equals(type.args().get(0)), "int64", null, null, null, null);
new JsonSchema(null, null, "integer", !(required != null && required) && !"long".equals(type.args().get(0)), "int64", null, null, null, null);
case "java.lang.String" ->
new JsonSchema(null, null, "string", true, null, null, null, null, null);
new JsonSchema(null, null, "string", !(required != null && required), null, null, null, null, null);
default -> {
final var schema = openRPC.schemas().computeIfAbsent(
type.args().get(0).replace('$', '.'),
k -> generateFullJsonSchema(type.args().get(0)));
final var id = schema.id() == null ? schema.ref() : schema.id();
yield new JsonSchema(
"#/schemas/" + requireNonNull(id, "missing id/ref: " + schema),
null, null, null, null, null, null, null, null);
null, null, (required != null && required) ? false : null, null, null, null, null, null);
}
}).asMap(),
null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,26 @@ public record JsonSchema(
Map<String, JsonSchema> properties,
JsonSchema items,
String title, String description,
List<String> enumeration) implements GenericObjectJsonSerializationLike {
List<String> enumeration,
List<String> required) implements GenericObjectJsonSerializationLike {
public JsonSchema(final String ref, final String id,
final String type, final Boolean nullable,
final String format, final String pattern,
final Object additionalProperties,
final Map<String, JsonSchema> properties,
final JsonSchema items,
final String title, final String description,
final List<String> enumeration) { // backward compat
this(ref, id, type, nullable, format, pattern, additionalProperties, properties, items, title, description, enumeration, null);
}

public JsonSchema(final String ref, final String id,
final String type, final Boolean nullable,
final String format, final String pattern,
final Object additionalProperties,
final Map<String, JsonSchema> properties,
final JsonSchema items) { // backward compat
this(ref, id, type, nullable, format, pattern, additionalProperties, properties, items, null, null, null);
this(ref, id, type, nullable, format, pattern, additionalProperties, properties, items, null, null, null, null);
}

@Override
Expand All @@ -54,6 +66,7 @@ public Map<String, Object> asMap() {
pattern == null ? null : entry("pattern", pattern),
additionalProperties == null ? null : entry("additionalProperties", additionalProperties),
nullable == null ? null : entry("nullable", nullable),
required == null || required.isEmpty() ? null : entry("required", required),
items == null ? null : entry("items", items.asMap()),
enumeration == null ? null : entry("enum", enumeration()),
properties == null ? null : entry("properties", properties.entrySet().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,7 @@ void incrementalCompilation(@TempDir final Path work) throws IOException {
new Compiler(work, "Bean21")
.compileAndAsserts((loader, container) -> assertEquals(7, container.getBeans().getBeans().size()));
}

@Test
void jsonRpcMetadata(@TempDir final Path work) throws IOException {
final var compiler = new Compiler(work, "JsonRpcEndpoints");
Expand Down Expand Up @@ -1676,7 +1677,9 @@ Stream<DynamicTest> jsonRpc(@TempDir final Path work) throws IOException {
"params": [
{
"name": "wrapper",
"required": true,
"schema": {
"nullable": false,
"$ref": "#/schemas/test.p.JsonRpcEndpoints.MyInput"
}
}
Expand Down
Loading