Skip to content

Commit c4475c4

Browse files
donbeavekobylynskyi
authored andcommitted
Add ability to generate particular types as Java interfaces #606 (#610)
* Gradle 6.8.3. * Added typesAsInterfaces config option. * Updated doc. * Basic implementation for generating type as interface. * Tests for generating type as interface. * Code style fixes. * Code style fixes. * Java 1.8 build fixes. * Code style fixes. * Code style fixes. * Attempt to fix compilation. * Code review fixes. (cherry picked from commit 994f6fe)
1 parent 7274453 commit c4475c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+928
-106
lines changed

docs/codegen-options.md

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* |
5454
| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data!|
5555
| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages.|
5656
| `generateModelOpenClasses` | Boolean | false | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future.|
57+
| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. |
5758

5859
### Option `graphqlSchemas`
5960

gradle/wrapper/gradle-wrapper.jar

509 Bytes
Binary file not shown.
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

gradlew

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ esac
8282

8383
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
8484

85+
8586
# Determine the Java command to use to start the JVM.
8687
if [ -n "$JAVA_HOME" ] ; then
8788
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
129130
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130131
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131132
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133+
132134
JAVACMD=`cygpath --unix "$JAVACMD"`
133135

134136
# We build the pattern for arguments to be converted via cygpath

gradlew.bat

+89-103
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,89 @@
1-
@rem
2-
@rem Copyright 2015 the original author or authors.
3-
@rem
4-
@rem Licensed under the Apache License, Version 2.0 (the "License");
5-
@rem you may not use this file except in compliance with the License.
6-
@rem You may obtain a copy of the License at
7-
@rem
8-
@rem https://www.apache.org/licenses/LICENSE-2.0
9-
@rem
10-
@rem Unless required by applicable law or agreed to in writing, software
11-
@rem distributed under the License is distributed on an "AS IS" BASIS,
12-
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
@rem See the License for the specific language governing permissions and
14-
@rem limitations under the License.
15-
@rem
16-
17-
@if "%DEBUG%" == "" @echo off
18-
@rem ##########################################################################
19-
@rem
20-
@rem Gradle startup script for Windows
21-
@rem
22-
@rem ##########################################################################
23-
24-
@rem Set local scope for the variables with windows NT shell
25-
if "%OS%"=="Windows_NT" setlocal
26-
27-
set DIRNAME=%~dp0
28-
if "%DIRNAME%" == "" set DIRNAME=.
29-
set APP_BASE_NAME=%~n0
30-
set APP_HOME=%DIRNAME%
31-
32-
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
33-
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34-
35-
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36-
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37-
38-
@rem Find java.exe
39-
if defined JAVA_HOME goto findJavaFromJavaHome
40-
41-
set JAVA_EXE=java.exe
42-
%JAVA_EXE% -version >NUL 2>&1
43-
if "%ERRORLEVEL%" == "0" goto init
44-
45-
echo.
46-
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47-
echo.
48-
echo Please set the JAVA_HOME variable in your environment to match the
49-
echo location of your Java installation.
50-
51-
goto fail
52-
53-
:findJavaFromJavaHome
54-
set JAVA_HOME=%JAVA_HOME:"=%
55-
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56-
57-
if exist "%JAVA_EXE%" goto init
58-
59-
echo.
60-
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61-
echo.
62-
echo Please set the JAVA_HOME variable in your environment to match the
63-
echo location of your Java installation.
64-
65-
goto fail
66-
67-
:init
68-
@rem Get command-line arguments, handling Windows variants
69-
70-
if not "%OS%" == "Windows_NT" goto win9xME_args
71-
72-
:win9xME_args
73-
@rem Slurp the command line arguments.
74-
set CMD_LINE_ARGS=
75-
set _SKIP=2
76-
77-
:win9xME_args_slurp
78-
if "x%~1" == "x" goto execute
79-
80-
set CMD_LINE_ARGS=%*
81-
82-
:execute
83-
@rem Setup the command line
84-
85-
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
86-
87-
@rem Execute Gradle
88-
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
89-
90-
:end
91-
@rem End local scope for the variables with windows NT shell
92-
if "%ERRORLEVEL%"=="0" goto mainEnd
93-
94-
:fail
95-
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
96-
rem the _cmd.exe /c_ return code!
97-
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
98-
exit /b 1
99-
100-
:mainEnd
101-
if "%OS%"=="Windows_NT" endlocal
102-
103-
:omega
1+
@rem
2+
@rem Copyright 2015 the original author or authors.
3+
@rem
4+
@rem Licensed under the Apache License, Version 2.0 (the "License");
5+
@rem you may not use this file except in compliance with the License.
6+
@rem You may obtain a copy of the License at
7+
@rem
8+
@rem https://www.apache.org/licenses/LICENSE-2.0
9+
@rem
10+
@rem Unless required by applicable law or agreed to in writing, software
11+
@rem distributed under the License is distributed on an "AS IS" BASIS,
12+
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
@rem See the License for the specific language governing permissions and
14+
@rem limitations under the License.
15+
@rem
16+
17+
@if "%DEBUG%" == "" @echo off
18+
@rem ##########################################################################
19+
@rem
20+
@rem Gradle startup script for Windows
21+
@rem
22+
@rem ##########################################################################
23+
24+
@rem Set local scope for the variables with windows NT shell
25+
if "%OS%"=="Windows_NT" setlocal
26+
27+
set DIRNAME=%~dp0
28+
if "%DIRNAME%" == "" set DIRNAME=.
29+
set APP_BASE_NAME=%~n0
30+
set APP_HOME=%DIRNAME%
31+
32+
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
33+
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34+
35+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36+
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37+
38+
@rem Find java.exe
39+
if defined JAVA_HOME goto findJavaFromJavaHome
40+
41+
set JAVA_EXE=java.exe
42+
%JAVA_EXE% -version >NUL 2>&1
43+
if "%ERRORLEVEL%" == "0" goto execute
44+
45+
echo.
46+
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47+
echo.
48+
echo Please set the JAVA_HOME variable in your environment to match the
49+
echo location of your Java installation.
50+
51+
goto fail
52+
53+
:findJavaFromJavaHome
54+
set JAVA_HOME=%JAVA_HOME:"=%
55+
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56+
57+
if exist "%JAVA_EXE%" goto execute
58+
59+
echo.
60+
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61+
echo.
62+
echo Please set the JAVA_HOME variable in your environment to match the
63+
echo location of your Java installation.
64+
65+
goto fail
66+
67+
:execute
68+
@rem Setup the command line
69+
70+
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71+
72+
73+
@rem Execute Gradle
74+
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75+
76+
:end
77+
@rem End local scope for the variables with windows NT shell
78+
if "%ERRORLEVEL%"=="0" goto mainEnd
79+
80+
:fail
81+
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82+
rem the _cmd.exe /c_ return code!
83+
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84+
exit /b 1
85+
86+
:mainEnd
87+
if "%OS%"=="Windows_NT" endlocal
88+
89+
:omega

plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java

+9
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
179179
@Parameter
180180
private String[] useObjectMapperForRequestSerialization;
181181

182+
@Parameter
183+
private String[] typesAsInterfaces;
184+
182185
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH_STRING)
183186
private int responseProjectionMaxDepth;
184187

@@ -247,6 +250,7 @@ public void execute() throws MojoExecutionException {
247250
mappingConfig.setParametrizedInputSuffix(parametrizedInputSuffix);
248251
mappingConfig.setResponseProjectionMaxDepth(responseProjectionMaxDepth);
249252
mappingConfig.setUseObjectMapperForRequestSerialization(mapToHashSet(useObjectMapperForRequestSerialization));
253+
mappingConfig.setTypesAsInterfaces(mapToHashSet(typesAsInterfaces));
250254

251255
mappingConfig.setResolverParentInterface(getResolverParentInterface());
252256
mappingConfig.setQueryResolverParentInterface(getQueryResolverParentInterface());
@@ -546,6 +550,11 @@ public Set<String> getUseObjectMapperForRequestSerialization() {
546550
return mapToHashSet(useObjectMapperForRequestSerialization);
547551
}
548552

553+
@Override
554+
public Set<String> getTypesAsInterfaces() {
555+
return mapToHashSet(typesAsInterfaces);
556+
}
557+
549558
@Override
550559
public String getQueryResolverParentInterface() {
551560
return parentInterfaces.getQueryResolver();

src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,22 @@ private List<File> generateType(MappingContext mappingContext, ExtendedObjectTyp
454454
List<File> generatedFiles = new ArrayList<>();
455455
Map<String, Object> dataModel = dataModelMapperFactory.getTypeDefinitionMapper()
456456
.map(mappingContext, definition);
457-
generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext,
458-
FreeMarkerTemplateType.TYPE, dataModel, outputDir));
457+
458+
boolean typeAsInterface = mappingConfig.getTypesAsInterfaces().contains(definition.getName());
459+
460+
if (!typeAsInterface) {
461+
typeAsInterface = definition.getDirectiveNames().stream().anyMatch(directiveName ->
462+
mappingConfig.getTypesAsInterfaces().contains("@" + directiveName)
463+
);
464+
}
465+
466+
if (typeAsInterface) {
467+
generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext,
468+
FreeMarkerTemplateType.INTERFACE, dataModel, outputDir));
469+
} else {
470+
generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext,
471+
FreeMarkerTemplateType.TYPE, dataModel, outputDir));
472+
}
459473

460474
if (Boolean.TRUE.equals(mappingConfig.getGenerateClient())) {
461475
Map<String, Object> responseProjDataModel = dataModelMapperFactory.getRequestResponseDefinitionMapper()

src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java

+15
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,21 @@ public interface GraphQLCodegenConfiguration {
401401
*/
402402
Set<String> getUseObjectMapperForRequestSerialization();
403403

404+
/**
405+
* Types that must generated as interfaces.
406+
*
407+
* <p>Values should be defined here in format: TypeName, @directive
408+
*
409+
* <p>E.g.:
410+
* <ul>
411+
* <li>{@code Person}</li>
412+
* <li>{@code @asInterface}</li>
413+
* </ul>
414+
*
415+
* @return Set of types that should generated as interfaces.
416+
*/
417+
Set<String> getTypesAsInterfaces();
418+
404419
/**
405420
* Generate code with lang
406421
*

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java

+12
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable<Ma
7373
private Integer responseProjectionMaxDepth;
7474
private Set<String> useObjectMapperForRequestSerialization = new HashSet<>();
7575

76+
private Set<String> typesAsInterfaces = new HashSet<>();
77+
7678
private boolean generateModelOpenClasses;
7779

7880
private GeneratedLanguage generatedLanguage;
@@ -173,6 +175,7 @@ public void combine(MappingConfig source) {
173175
GraphQLCodegenConfiguration::getResponseProjectionMaxDepth);
174176
useObjectMapperForRequestSerialization = combineSet(useObjectMapperForRequestSerialization,
175177
source.useObjectMapperForRequestSerialization);
178+
typesAsInterfaces = combineSet(typesAsInterfaces, source.typesAsInterfaces);
176179
generatedLanguage = getValueOrDefaultToThis(source, GraphQLCodegenConfiguration::getGeneratedLanguage);
177180
generateModelOpenClasses = getValueOrDefaultToThis(source,
178181
GraphQLCodegenConfiguration::isGenerateModelOpenClasses);
@@ -602,6 +605,15 @@ public void setUseObjectMapperForRequestSerialization(Set<String> useObjectMappe
602605
this.useObjectMapperForRequestSerialization = useObjectMapperForRequestSerialization;
603606
}
604607

608+
@Override
609+
public Set<String> getTypesAsInterfaces() {
610+
return typesAsInterfaces;
611+
}
612+
613+
public void setTypesAsInterfaces(Set<String> typesAsInterfaces) {
614+
this.typesAsInterfaces = typesAsInterfaces;
615+
}
616+
605617
@Override
606618
public GeneratedLanguage getGeneratedLanguage() {
607619
return generatedLanguage;

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java

+5
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ public Set<String> getUseObjectMapperForRequestSerialization() {
277277
return config.getUseObjectMapperForRequestSerialization();
278278
}
279279

280+
@Override
281+
public Set<String> getTypesAsInterfaces() {
282+
return config.getTypesAsInterfaces();
283+
}
284+
280285
public ExtendedDocument getDocument() {
281286
return document;
282287
}

0 commit comments

Comments
 (0)