Skip to content
Draft
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ client/shade/dependency-reduced-pom.xml
# mkdocs output
site


# agents
.claude
.playwright-mcp
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,6 @@ ui/graphiql/ -> GraphiQL UI component

- Jakarta namespace only — the build enforces a ban on `javax.*` dependencies via maven-enforcer-plugin
- Logging uses `jboss-logging` with message localization (`SmallRyeGraphQLServerLogging`, `SmallRyeGraphQLServerMessages`)
- JSON binding uses JSON-B (Yasson implementation), not Jackson
- JSON processing uses Jackson 3.x (tools.jackson). JSON-B annotations are supported via the jackson-jsonb-compat module
- The `.mvn/` directory is gitignored and may contain local Maven settings (repo path, mirrors)
- The graphql-java library (currently v21.1) is the underlying GraphQL execution engine
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.eclipse.microprofile.graphql.Query;

import io.smallrye.graphql.api.Namespace;
import io.smallrye.graphql.api.Subscription;
import io.smallrye.graphql.client.core.OperationType;
import io.smallrye.graphql.client.model.MethodKey;
import io.smallrye.graphql.client.typesafe.api.Multiple;
Expand Down Expand Up @@ -67,7 +66,8 @@ public OperationType getOperationType() {
if (method.isAnnotationPresent(Mutation.class)) {
return OperationType.MUTATION;
}
if (method.isAnnotationPresent(Subscription.class)) {
if (method.isAnnotationPresent(org.eclipse.microprofile.graphql.Subscription.class)
|| method.isAnnotationPresent(io.smallrye.graphql.api.Subscription.class)) {
return OperationType.SUBSCRIPTION;
}
return OperationType.QUERY;
Expand Down Expand Up @@ -99,9 +99,18 @@ private Optional<String> mutationName() {
}

private Optional<String> subscriptionName() {
Subscription annotation = method.getAnnotation(Subscription.class);
if (annotation != null && !annotation.value().isEmpty())
return Optional.of(annotation.value());
// Check MicroProfile annotation first (preferred)
org.eclipse.microprofile.graphql.Subscription mpAnnotation = method
.getAnnotation(org.eclipse.microprofile.graphql.Subscription.class);
if (mpAnnotation != null && !mpAnnotation.value().isEmpty())
return Optional.of(mpAnnotation.value());

// Fall back to deprecated SmallRye annotation
io.smallrye.graphql.api.Subscription srAnnotation = method
.getAnnotation(io.smallrye.graphql.api.Subscription.class);
if (srAnnotation != null && !srAnnotation.value().isEmpty())
return Optional.of(srAnnotation.value());

return Optional.empty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ private static Map<DotName, AnnotationInstance> getAnnotationsWithFilter(Type ty
.createSimple("io.smallrye.graphql.client.typesafe.api.GraphQLClientApi");
public static final DotName QUERY = DotName.createSimple("org.eclipse.microprofile.graphql.Query");
public static final DotName MUTATION = DotName.createSimple("org.eclipse.microprofile.graphql.Mutation");
public static final DotName SUBSCRIPTION = DotName.createSimple("org.eclipse.microprofile.graphql.Subscription");
public static final DotName INPUT = DotName.createSimple("org.eclipse.microprofile.graphql.Input");
public static final DotName TYPE = DotName.createSimple("org.eclipse.microprofile.graphql.Type");
public static final DotName INTERFACE = DotName.createSimple("org.eclipse.microprofile.graphql.Interface");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ public static boolean isStringScalar(String className) {
populateScalar(URL.class.getName(), STRING);
populateScalar(URI.class.getName(), STRING);
populateScalar("org.bson.types.ObjectId", STRING);
populateScalar("javax.json.JsonObject", STRING);
populateScalar("javax.json.JsonArray", STRING);
populateScalar("jakarta.json.JsonObject", STRING);
populateScalar("jakarta.json.JsonArray", STRING);

// Boolean
populateScalar(Boolean.class.getName(), BOOLEAN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static io.smallrye.graphql.client.modelbuilder.Annotations.NAMESPACE;
import static io.smallrye.graphql.client.modelbuilder.Annotations.QUERY;
import static io.smallrye.graphql.client.modelbuilder.Annotations.SUBCRIPTION;
import static io.smallrye.graphql.client.modelbuilder.Annotations.SUBSCRIPTION;
import static io.smallrye.graphql.client.modelbuilder.ScanningContext.getIndex;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -201,7 +202,7 @@ public OperationType getOperationType() {
if (method.hasAnnotation(MUTATION)) {
return OperationType.MUTATION;
}
if (method.hasAnnotation(SUBCRIPTION)) {
if (method.hasAnnotation(SUBSCRIPTION) || method.hasAnnotation(SUBCRIPTION)) {
return OperationType.SUBSCRIPTION;
}
return OperationType.QUERY;
Expand Down Expand Up @@ -236,14 +237,23 @@ public Optional<String> mutationName() {
}

/**
* Gets the name of the GraphQL subscription, considering any io.smallrye.graphql.api.Subscription annotation.
* Gets the name of the GraphQL subscription, considering any {@code @Subscription} annotation
* (either {@link org.eclipse.microprofile.graphql.Subscription} or
* {@link io.smallrye.graphql.api.Subscription}).
*
* @return An optional containing the subscription name if specified, otherwise empty.
*/
public Optional<String> subscriptionName() {
Optional<AnnotationInstance> subscriptionAnnotation = getMethodAnnotation(SUBCRIPTION);
// Check MicroProfile annotation first (preferred)
Optional<AnnotationInstance> subscriptionAnnotation = getMethodAnnotation(SUBSCRIPTION);
if (subscriptionAnnotation.isPresent() && subscriptionAnnotation.orElseThrow().value() != null)
return Optional.of(subscriptionAnnotation.orElseThrow().value().asString());

// Fall back to deprecated SmallRye annotation
subscriptionAnnotation = getMethodAnnotation(SUBCRIPTION);
if (subscriptionAnnotation.isPresent() && subscriptionAnnotation.orElseThrow().value() != null)
return Optional.of(subscriptionAnnotation.orElseThrow().value().asString());

return Optional.empty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ private static Map<DotName, AnnotationInstance> getAnnotationsWithFilter(org.jbo
public static final DotName GRAPHQL_API = DotName.createSimple("org.eclipse.microprofile.graphql.GraphQLApi");
public static final DotName QUERY = DotName.createSimple("org.eclipse.microprofile.graphql.Query");
public static final DotName MUTATION = DotName.createSimple("org.eclipse.microprofile.graphql.Mutation");
public static final DotName SUBSCRIPTION = DotName.createSimple("org.eclipse.microprofile.graphql.Subscription");
public static final DotName INPUT = DotName.createSimple("org.eclipse.microprofile.graphql.Input");
public static final DotName TYPE = DotName.createSimple("org.eclipse.microprofile.graphql.Type");
public static final DotName INTERFACE = DotName.createSimple("org.eclipse.microprofile.graphql.Interface");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ private static boolean isAsyncType(Type type) {
|| type.name().equals(COMPLETION_STAGE)
|| type.name().equals(UNI)
|| type.name().equals(MULTI)
|| type.name().equals(PUBLISHER);
|| type.name().equals(PUBLISHER)
|| type.name().equals(FLOW_PUBLISHER);
}

/**
Expand Down Expand Up @@ -267,6 +268,7 @@ public static boolean isUnwrappedType(Type type) {
private static final DotName MULTI = DotName.createSimple("io.smallrye.mutiny.Multi");
@Deprecated
private static final DotName PUBLISHER = DotName.createSimple("org.reactivestreams.Publisher");
private static final DotName FLOW_PUBLISHER = DotName.createSimple("java.util.concurrent.Flow$Publisher");

public static final DotName SERIALIZABLE = DotName.createSimple(Serializable.class.getName());
public static final DotName OBJECT = DotName.createSimple(Object.class.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ private void validateSubscriptions(Collection<AnnotationInstance> graphQLApiAnno
List<MethodInfo> methods = getAllMethodsIncludingFromSuperClasses(apiClass);
for (MethodInfo methodInfo : methods) {
Annotations annotationsForMethod = Annotations.getAnnotationsForMethod(methodInfo);
if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) {
if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBSCRIPTION, Annotations.SUBCRIPTION)) {
errors.add("class: " + apiClass.name().toString() + ", method: " + methodInfo.name());
}
}
Expand Down Expand Up @@ -450,7 +450,7 @@ private void addOperations(Schema schema, List<MethodInfo> methodInfoList) {
} else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.MUTATION)) {
Operation mutation = operationCreator.createOperation(methodInfo, OperationType.MUTATION, null);
schema.addMutation(mutation);
} else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBCRIPTION)) {
} else if (annotationsForMethod.containsOneOfTheseAnnotations(Annotations.SUBSCRIPTION, Annotations.SUBCRIPTION)) {
Operation subscription = operationCreator.createOperation(methodInfo, OperationType.SUBSCRIPTION, null);
schema.addSubscription(subscription);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,18 @@ public Operation createOperation(MethodInfo methodInfo, OperationType operationT
Type fieldType = getReturnType(methodInfo);

// Name
String name = getOperationName(methodInfo, operationType, annotationsForMethod);
// For source operations, find the @Source parameter to extract custom field name
Annotations sourceParameterAnnotations = null;
if (type != null) { // This is a source operation
for (short i = 0; i < methodInfo.parametersCount(); i++) {
Annotations paramAnnotations = Annotations.getAnnotationsForArgument(methodInfo, i);
if (paramAnnotations.containsOneOfTheseAnnotations(Annotations.SOURCE)) {
sourceParameterAnnotations = paramAnnotations;
break;
}
}
}
String name = getOperationName(methodInfo, operationType, annotationsForMethod, sourceParameterAnnotations);

// Field Type
validateFieldType(methodInfo, operationType);
Expand Down Expand Up @@ -273,25 +284,56 @@ private static void validateFieldType(MethodInfo methodInfo, OperationType opera

/**
* Get the name from annotation(s) or default.
* This is for operations (query, mutation and source)
*
* @param methodInfo the java method
* @param operationType the type (query, mutation)
* @param operationType the type (query, mutation, subscription)
* @param annotations the annotations on this method
* @param sourceParameterAnnotations annotations for the @Source parameter (null for top-level operations)
* @return the operation name
*/
private static String getOperationName(MethodInfo methodInfo, OperationType operationType, Annotations annotations) {
private static String getOperationName(MethodInfo methodInfo, OperationType operationType, Annotations annotations,
Annotations sourceParameterAnnotations) {
// For source operations, check the @Source annotation's value() and name() attributes first
if (sourceParameterAnnotations != null) {
Optional<AnnotationInstance> sourceAnnotation = sourceParameterAnnotations
.getOneOfTheseAnnotations(Annotations.SOURCE);
if (sourceAnnotation.isPresent()) {
AnnotationInstance source = sourceAnnotation.get();

// Try value() first (current preferred way per MicroProfile GraphQL 2.1)
if (source.value("value") != null) {
String valueAttr = source.value("value").asString();
if (valueAttr != null && !valueAttr.isEmpty()) {
return valueAttr;
}
}

// Fall back to name() (deprecated but still supported)
if (source.value("name") != null) {
String nameAttr = source.value("name").asString();
if (nameAttr != null && !nameAttr.isEmpty()) {
return nameAttr;
}
}
}
}

DotName operationAnnotation = getOperationAnnotation(operationType);

// If the @Query or @Mutation annotation has a value, use that, else use name or jsonb property
return annotations.getOneOfTheseMethodAnnotationsValue(
// If the @Query, @Mutation, or @Subscription annotation has a value, use that, else use name or jsonb property
Optional<String> name = annotations.getOneOfTheseMethodAnnotationsValue(
operationAnnotation,
Annotations.NAME,
Annotations.JAKARTA_JSONB_PROPERTY,
Annotations.JAVAX_JSONB_PROPERTY,
Annotations.JACKSON_PROPERTY)
.orElse(getDefaultExecutionTypeName(methodInfo, operationType));
Annotations.JACKSON_PROPERTY);

// For subscriptions, also check the deprecated SmallRye annotation
if (name.isEmpty() && operationType == OperationType.SUBSCRIPTION) {
name = annotations.getOneOfTheseMethodAnnotationsValue(Annotations.SUBCRIPTION);
}

return name.orElse(getDefaultExecutionTypeName(methodInfo, operationType));
}

private static DotName getOperationAnnotation(OperationType operationType) {
Expand All @@ -301,7 +343,7 @@ private static DotName getOperationAnnotation(OperationType operationType) {
case MUTATION:
return Annotations.MUTATION;
case SUBSCRIPTION:
return Annotations.SUBCRIPTION;
return Annotations.SUBSCRIPTION;
case RESOLVER:
return Annotations.RESOLVER;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,9 @@ public static void addObject() {
}

public static void addJson() {
populateScalar("jakarta.json.JsonValue", JSON, Object.class.getName());
populateScalar("jakarta.json.JsonObject", JSON, Object.class.getName());
populateScalar("tools.jackson.databind.JsonNode", JSON, Object.class.getName());
populateScalar("tools.jackson.databind.node.ObjectNode", JSON, Object.class.getName());
populateScalar("tools.jackson.databind.node.ArrayNode", JSON, Object.class.getName());
}

static {
Expand All @@ -138,10 +137,6 @@ public static void addJson() {
populateScalar(URL.class.getName(), STRING, String.class.getName());
populateScalar(URI.class.getName(), STRING, String.class.getName());
populateScalar("org.bson.types.ObjectId", STRING, String.class.getName());
populateScalar("javax.json.JsonObject", STRING, String.class.getName());
populateScalar("javax.json.JsonArray", STRING, String.class.getName());
populateScalar("jakarta.json.JsonObject", STRING, String.class.getName());
populateScalar("jakarta.json.JsonArray", STRING, String.class.getName());

// Boolean
populateScalar(Boolean.class.getName(), BOOLEAN);
Expand Down
24 changes: 2 additions & 22 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@

<properties>
<version.eclipse.microprofile.config>3.1.1</version.eclipse.microprofile.config>
<version.eclipse.microprofile.graphql>2.0</version.eclipse.microprofile.graphql>
<!-- <version.eclipse.microprofile.graphql-client>2.1-SNAPSHOT</version.eclipse.microprofile.graphql-client>-->
<version.eclipse.microprofile.graphql>2.1-SNAPSHOT</version.eclipse.microprofile.graphql>
<version.eclipse.microprofile.context-propagation>1.3</version.eclipse.microprofile.context-propagation>
<version.jandex>3.5.3</version.jandex>
<version.smallrye-config>3.17.2</version.smallrye-config>
Expand Down Expand Up @@ -108,31 +107,12 @@
</exclusions>
</dependency>

<!-- Client API is copied into SmallRye for now -->
<!-- <dependency>
<groupId>org.eclipse.microprofile.graphql</groupId>
<artifactId>microprofile-graphql-client-api</artifactId>
<version>${version.eclipse.microprofile.graphql-client}</version>
</dependency>

<dependency>
<groupId>org.eclipse.microprofile.graphql</groupId>
<artifactId>microprofile-graphql-client-tck</artifactId>
<version>${version.eclipse.microprofile.graphql-client}</version>
</dependency>
-->
<dependency>
<groupId>org.eclipse.microprofile.graphql</groupId>
<artifactId>microprofile-graphql-tck</artifactId>
<version>${version.eclipse.microprofile.graphql}</version>
</dependency>

<dependency>
<groupId>org.eclipse.microprofile.graphql</groupId>
<artifactId>microprofile-graphql-server-tck</artifactId>
<version>${version.eclipse.microprofile.graphql}</version>
</dependency>


<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
Expand Down
6 changes: 3 additions & 3 deletions server/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@
<artifactId>smallrye-common-annotation</artifactId>
</dependency>

<!-- From other MP Platform apis -->
<!-- Jackson for Context API types -->
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Expand Down
Loading
Loading