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
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,26 @@ GraphQLObjectType object = GraphQLAnnotations.object(SomeObject.class);

## Defining Interfaces

This is very similar to defining objects:
This is very similar to defining objects, with the addition of type resolver :

```java
@GraphQLTypeResolver(MyTypeResolver.class)
public interface SomeInterface {
@GraphQLField
String field();
}

public class MyTypeResolver implements TypeResolver {
GraphQLObjectType getType(TypeResolutionEnvironment env) { ... }
}

// ...
GraphQLInterfaceType object = GraphQLAnnotations.iface(SomeInterface.class);
```

An instance of the type resolver will be created from the specified class. If a `getInstance` method is present on the
class, it will be used instead of the default constructor.

## Fields

In addition to specifying a field over a Java class field, a field can be defined over a method:
Expand Down Expand Up @@ -108,10 +116,21 @@ public String field(@GraphQLDefaultValue(DefaultValue.class) String value) {
}
```

The `DefaultValue` class can define a `getInstance` method that will be called instead of the default constructor.

`@GraphQLDeprecate` and Java's `@Deprecated` can be used to specify a deprecated
field.

You can specify a custom data fetcher for a field with `@GraphQLDataFetcher`
### Custom data fetcher

You can specify a custom data fetcher for a field with `@GraphQLDataFetcher`. The annotation will reference a class name,
which will be used as data fetcher.

An instance of the data fetcher will be created. The `args` attribute on the annotation can be used to specify a list of
String arguments to pass to the construcor, allowing to reuse the same class on different fields, with different parameter.
The `firstArgIsTargetName` attribute can also be set on `@GraphQLDataFetcher` to pass the field name as a single parameter of the constructor.

If no argument is needed and a `getInstance` method is present, this method will be called instead of the constructor.

## Type extensions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
* A package level helper in calling reflective methods and turning them into
Expand All @@ -26,8 +28,16 @@
public class ReflectionKit {
public static <T> T newInstance(Class<T> clazz) throws GraphQLAnnotationsException {
try {
try {
Method getInstance = clazz.getMethod("getInstance", new Class<?>[0]);
if (Modifier.isStatic(getInstance.getModifiers()) && clazz.isAssignableFrom(getInstance.getReturnType())) {
return (T) getInstance.invoke(null);
}
} catch (NoSuchMethodException e) {
// ignore, just call the constructor
}
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
} catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new GraphQLAnnotationsException("Unable to instantiate class : " + clazz, e);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/graphql/annotations/GraphQLInterfaceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public void noResolver() {

public static class Resolver implements TypeResolver {

public static Resolver getInstance() {
return new Resolver();
}

@Override
public GraphQLObjectType getType(TypeResolutionEnvironment env) {
try {
Expand Down