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

#1423: add GraphQLResult and wrap successful result #1424

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ private static Map<DotName, AnnotationInstance> getAnnotationsWithFilter(org.jbo
public static final DotName DIRECTIVE = DotName.createSimple("io.smallrye.graphql.api.Directive");
public static final DotName DEFAULT_NON_NULL = DotName.createSimple("io.smallrye.graphql.api.DefaultNonNull");
public static final DotName NULLABLE = DotName.createSimple("io.smallrye.graphql.api.Nullable");
public static final DotName RESULT = DotName.createSimple("io.smallrye.graphql.api.GraphQLResult");

// MicroProfile GraphQL Annotations
public static final DotName GRAPHQL_API = DotName.createSimple("org.eclipse.microprofile.graphql.GraphQLApi");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.smallrye.graphql.schema.creator;

import java.util.List;

import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
Expand All @@ -15,10 +17,11 @@
import io.smallrye.graphql.schema.helper.NonNullHelper;
import io.smallrye.graphql.schema.helper.TypeAutoNameStrategy;
import io.smallrye.graphql.schema.model.Field;
import io.smallrye.graphql.schema.model.Operation;

/**
* Abstract creator
*
*
* @author Phillip Kruger (phillip.kruger@redhat.com)
*/
public abstract class ModelCreator {
Expand All @@ -43,36 +46,30 @@ public TypeAutoNameStrategy getTypeAutoNameStrategy() {
}

/**
* The the return type.This is usually the method return type, but can also be adapted to something else
*
* @param methodInfo method
* @return the return type
* The return type. This is usually the method return type, but can also be adapted to something else
*/
protected static Type getReturnType(MethodInfo methodInfo) {
return methodInfo.returnType();
}

/**
* The the return type.This is usually the method return type, but can also be adapted to something else
*
* @param fieldInfo
* @return the return type
* The return type. This is usually the method return type, but can also be adapted to something else
*/
protected static Type getReturnType(FieldInfo fieldInfo) {
return fieldInfo.type();

}

protected void populateField(Direction direction, Field field, Type type, Annotations annotations) {
// Wrapper
field.setWrapper(WrapperCreator.createWrapper(type).orElse(null));
List<String> declaredErrors = (field instanceof Operation) ? ((Operation) field).getDeclaredErrors() : null;
field.setWrapper(WrapperCreator.createWrapper(null, type, annotations, declaredErrors).orElse(null));

doPopulateField(direction, field, type, annotations);
}

protected void populateField(Direction direction, Field field, Type fieldType, Type methodType, Annotations annotations) {
// Wrapper
field.setWrapper(WrapperCreator.createWrapper(fieldType, methodType).orElse(null));
field.setWrapper(WrapperCreator.createWrapper(fieldType, methodType, annotations).orElse(null));

doPopulateField(direction, field, methodType, annotations);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public OperationCreator(ReferenceCreator referenceCreator, ArgumentCreator argum
*
* @param methodInfo the java method
* @param operationType the type of operation (Query / Mutation)
* @param type
* @param type the GraphQL type of the operation
* @return a Operation that defines this GraphQL Operation
*/
public Operation createOperation(MethodInfo methodInfo, OperationType operationType,
Expand Down Expand Up @@ -84,11 +84,24 @@ public Operation createOperation(MethodInfo methodInfo, OperationType operationT
maybeArgument.ifPresent(operation::addArgument);
}

// Declared Throwables
methodInfo.exceptions().stream().map(this::toError).forEach(operation::addDeclaredError);

populateField(Direction.OUT, operation, fieldType, annotationsForMethod);

return operation;
}

private String toError(Type type) {
var name = type.name().toString();
name = name.substring(name.lastIndexOf('.') + 1);
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
if (name.endsWith("Exception")) {
name = name.substring(0, name.length() - 9);
}
return name;
}

private static void validateFieldType(MethodInfo methodInfo, OperationType operationType) {
Type returnType = methodInfo.returnType();
if (returnType.kind().equals(Type.Kind.VOID)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package io.smallrye.graphql.schema.creator;

import static java.util.Collections.emptyList;

import java.util.List;
import java.util.Optional;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.Type;

import io.smallrye.graphql.schema.Annotations;
import io.smallrye.graphql.schema.Classes;
import io.smallrye.graphql.schema.ScanningContext;
import io.smallrye.graphql.schema.helper.NonNullHelper;
import io.smallrye.graphql.schema.model.Wrapper;
import io.smallrye.graphql.schema.model.WrapperType;
Expand All @@ -22,29 +28,43 @@ public class WrapperCreator {
private WrapperCreator() {
}

public static Optional<Wrapper> createWrapper(Type type) {
return createWrapper(null, type);
public static Optional<Wrapper> createWrapper(Type type, Annotations annotations) {
return createWrapper(null, type, annotations);
}

public static Optional<Wrapper> createWrapper(Type fieldType, Type methodType, Annotations annotations) {
return createWrapper(fieldType, methodType, annotations, emptyList());
}

/**
* Create a Wrapper for a Field (that has properties and methods)
*
*
* @param fieldType the java field type
* @param methodType the java method type
* @return optional array
* @param annotations the annotations on the method
* @param declaredErrors the errors that the method declares
* @return optional Wrapper
*/
public static Optional<Wrapper> createWrapper(Type fieldType, Type methodType) {
public static Optional<Wrapper> createWrapper(Type fieldType, Type methodType, Annotations annotations,
List<String> declaredErrors) {
Optional<AnnotationInstance> resultAnnotation = annotations.getOneOfTheseAnnotations(Annotations.RESULT);
if (resultAnnotation.isPresent()) {
AnnotationValue mode = resultAnnotation.get().valueWithDefault(ScanningContext.getIndex(), "mode");
if ("ERROR_FIELDS".equals(mode.asString())) {
Wrapper wrapper = new Wrapper(WrapperType.RESULT, methodType.name().toString(), true);
wrapper.setDeclaredErrors(declaredErrors);
return Optional.of(wrapper);
}
}
if (Classes.isWrapper(methodType)) {
Wrapper wrapper = new Wrapper(getWrapperType(methodType), methodType.name().toString());
// NotNull
if (markParameterizedTypeNonNull(fieldType, methodType)) {
wrapper.setNotEmpty(true);
wrapper.setNonNull(true);
}
// Wrapper of wrapper
Optional<Wrapper> wrapperOfWrapper = getWrapperOfWrapper(methodType);
if (wrapperOfWrapper.isPresent()) {
wrapper.setWrapper(wrapperOfWrapper.get());
}
Optional<Wrapper> wrapperOfWrapper = getWrapperOfWrapper(methodType, annotations);
wrapperOfWrapper.ifPresent(wrapper::setWrapper);

return Optional.of(wrapper);
}
Expand All @@ -66,13 +86,13 @@ private static WrapperType getWrapperType(Type type) {
return null;
}

private static Optional<Wrapper> getWrapperOfWrapper(Type type) {
private static Optional<Wrapper> getWrapperOfWrapper(Type type, Annotations annotations) {
if (Classes.isArray(type)) {
Type typeInArray = type.asArrayType().component();
return createWrapper(typeInArray);
return createWrapper(typeInArray, annotations);
} else if (Classes.isParameterized(type)) {
Type typeInCollection = type.asParameterizedType().arguments().get(0);
return createWrapper(typeInCollection);
return createWrapper(typeInCollection, annotations);
}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,19 @@ public static Optional<AdaptWith> getAdaptWith(Direction direction, ReferenceCre
Type from = arguments.get(0);
Type to = arguments.get(1);
adaptWith.setAdapterClass(type.name().toString());
r.setWrapper(WrapperCreator.createWrapper(from).orElse(null));
r.setWrapper(WrapperCreator.createWrapper(from, annotations).orElse(null));
adaptWith.setFromReference(r);

if (Scalars.isScalar(to.name().toString())) {
adaptWith.setToReference(Scalars.getScalar(to.name().toString()));
} else {
Annotations annotationsAplicableToMe = annotations.removeAnnotations(Annotations.ADAPT_WITH,
Annotations annotationsApplicableToMe = annotations.removeAnnotations(Annotations.ADAPT_WITH,
Annotations.JAKARTA_JSONB_TYPE_ADAPTER, Annotations.JAVAX_JSONB_TYPE_ADAPTER);

// Remove the adaption annotation, as this is the type being adapted to
Reference toRef = referenceCreator.createReferenceForAdapter(to,
annotationsAplicableToMe, direction);
toRef.setWrapper(WrapperCreator.createWrapper(to).orElse(null));
annotationsApplicableToMe, direction);
toRef.setWrapper(WrapperCreator.createWrapper(to, annotations).orElse(null));

adaptWith.setToReference(toRef);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.smallrye.graphql.schema.model;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

Expand Down Expand Up @@ -41,6 +42,12 @@ public final class Operation extends Field {
*/
private Execute execute;

/**
* The error codes that the method declares to throw.
* This is required to build the <code>error</code> fields for a <code>GraphQLResult</code>.
*/
private List<String> declaredErrors;

public Operation() {
}

Expand Down Expand Up @@ -104,9 +111,20 @@ public void setExecute(Execute execute) {
this.execute = execute;
}

public List<String> getDeclaredErrors() {
return declaredErrors;
}

public void addDeclaredError(String error) {
if (this.declaredErrors == null) {
this.declaredErrors = new ArrayList<>();
}
this.declaredErrors.add(error);
}

@Override
public String toString() {
return "Operation{" + "className=" + className + ", arguments=" + arguments + ", operationType=" + operationType
+ ", sourceFieldOn=" + sourceFieldOn + '}';
+ ", sourceFieldOn=" + sourceFieldOn + ", declaredErrors=" + declaredErrors + '}';
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package io.smallrye.graphql.schema.model;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

/**
* If the type is wrapped in a generics bucket or in an array, keep the info here.
*
*
* @author Phillip Kruger (phillip.kruger@redhat.com)
*/
public class Wrapper implements Serializable {

private String wrapperClassName;
private boolean notEmpty = false; // Mark this to be not empty
private boolean nonNull = false; // Mark this to be non-null
private WrapperType wrapperType = WrapperType.UNKNOWN;
private List<String> declaredErrors;

private Wrapper wrapper = null;

Expand All @@ -24,10 +26,10 @@ public Wrapper(WrapperType wrapperType, String wrapperClassName) {
this.wrapperClassName = wrapperClassName;
}

public Wrapper(WrapperType wrapperType, String wrapperClassName, boolean notEmpty) {
public Wrapper(WrapperType wrapperType, String wrapperClassName, boolean nonNull) {
this.wrapperType = wrapperType;
this.wrapperClassName = wrapperClassName;
this.notEmpty = notEmpty;
this.nonNull = nonNull;
}

public WrapperType getWrapperType() {
Expand All @@ -46,12 +48,20 @@ public void setWrapperClassName(String wrapperClassName) {
this.wrapperClassName = wrapperClassName;
}

public void setNotEmpty(boolean notEmpty) {
this.notEmpty = notEmpty;
public void setNonNull(boolean nonNull) {
this.nonNull = nonNull;
}

public boolean isNotEmpty() {
return this.notEmpty;
public boolean isNonNull() {
return this.nonNull;
}

public List<String> getDeclaredErrors() {
return declaredErrors;
}

public void setDeclaredErrors(List<String> declaredErrors) {
this.declaredErrors = declaredErrors;
}

public Wrapper getWrapper() {
Expand Down Expand Up @@ -86,23 +96,28 @@ public boolean isOptional() {
return wrapperType.equals(WrapperType.OPTIONAL);
}

public boolean isResult() {
return wrapperType.equals(WrapperType.RESULT);
}

public boolean isUnknown() {
return wrapperType.equals(WrapperType.UNKNOWN);
}

@Override
public String toString() {
return "Wrapper{" + "wrapperClassName=" + wrapperClassName + ", notEmpty=" + notEmpty + ", wrapperType=" + wrapperType
+ ", wrapper=" + wrapper + '}';
return "Wrapper{" + "wrapperClassName=" + wrapperClassName + ", nonNull=" + nonNull + ", wrapperType=" + wrapperType
+ ", wrapper=" + wrapper + ", declaredErrors=" + declaredErrors + '}';
}

@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.wrapperClassName);
hash = 59 * hash + (this.notEmpty ? 1 : 0);
hash = 59 * hash + (this.nonNull ? 1 : 0);
hash = 59 * hash + Objects.hashCode(this.wrapperType);
hash = 59 * hash + Objects.hashCode(this.wrapper);
hash = 59 * hash + Objects.hashCode(this.declaredErrors);
return hash;
}

Expand All @@ -118,7 +133,7 @@ public boolean equals(Object obj) {
return false;
}
final Wrapper other = (Wrapper) obj;
if (this.notEmpty != other.notEmpty) {
if (this.nonNull != other.nonNull) {
return false;
}
if (!Objects.equals(this.wrapperClassName, other.wrapperClassName)) {
Expand All @@ -130,6 +145,9 @@ public boolean equals(Object obj) {
if (!Objects.equals(this.wrapper, other.wrapper)) {
return false;
}
if (!Objects.equals(this.declaredErrors, other.declaredErrors)) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package io.smallrye.graphql.schema.model;

/**
* Represent an wrapper type in the Schema.
*
* Represent a wrapper type in the Schema.
*
* @author Phillip Kruger (phillip.kruger@redhat.com)
*/
public enum WrapperType {
OPTIONAL,
COLLECTION,
MAP,
ARRAY,
RESULT, // see GraphQLResult
UNKNOWN // Could be a plugged in type, or normal generics
}
}
Loading