@graphql-codegen/java
Version:
GraphQL Code Generator plugin for generating Java code based on a GraphQL schema
237 lines (232 loc) • 10.2 kB
JavaScript
import { isEnumType, isInputObjectType, isScalarType, Kind, } from 'graphql';
import { JAVA_SCALARS, JavaDeclarationBlock, wrapTypeWithModifiers, } from '@graphql-codegen/java-common';
import { BaseVisitor, buildScalarsFromConfig, getBaseTypeNode, indent, indentMultiline, } from '@graphql-codegen/visitor-plugin-common';
export class JavaResolversVisitor extends BaseVisitor {
constructor(rawConfig, _schema, defaultPackageName) {
super(rawConfig, {
enumValues: rawConfig.enumValues || {},
listType: rawConfig.listType || 'Iterable',
className: rawConfig.className || 'Types',
classMembersPrefix: rawConfig.classMembersPrefix || '',
package: rawConfig.package || defaultPackageName,
scalars: buildScalarsFromConfig(_schema, rawConfig, JAVA_SCALARS, 'Object'),
useEmptyCtor: rawConfig.useEmptyCtor || false,
});
this._schema = _schema;
this._addHashMapImport = false;
this._addMapImport = false;
this._addListImport = false;
}
getImports() {
const allImports = [];
if (this._addHashMapImport) {
allImports.push(`java.util.HashMap`);
}
if (this._addMapImport) {
allImports.push(`java.util.Map`);
}
if (this._addListImport) {
allImports.push(`java.util.List`);
allImports.push(`java.util.stream.Collectors`);
}
return allImports.map(i => `import ${i};`).join('\n') + '\n';
}
wrapWithClass(content) {
return new JavaDeclarationBlock()
.access('public')
.asKind('class')
.withName(this.config.className)
.withBlock(indentMultiline(content)).string;
}
getPackageName() {
return `package ${this.config.package};\n`;
}
getEnumValue(enumName, enumOption) {
if (this.config.enumValues[enumName] &&
typeof this.config.enumValues[enumName] === 'object' &&
this.config.enumValues[enumName][enumOption]) {
return this.config.enumValues[enumName][enumOption];
}
return enumOption;
}
EnumValueDefinition(node) {
return (enumName) => {
return indent(`${this.getEnumValue(enumName, node.name.value)}`);
};
}
EnumTypeDefinition(node) {
this._addHashMapImport = true;
this._addMapImport = true;
const enumName = this.convertName(node.name);
const enumValues = node.values
.map(enumValue => {
const a = enumValue(node.name.value);
// replace reserved word new
if (a.trim() === 'new') {
return '_new';
}
return a;
})
.join(',\n');
const enumCtor = indentMultiline(``);
const enumBlock = [enumValues, enumCtor].join('\n');
return new JavaDeclarationBlock()
.access('public')
.asKind('enum')
.withComment(node.description)
.withName(enumName)
.withBlock(enumBlock).string;
}
resolveInputFieldType(typeNode) {
const innerType = getBaseTypeNode(typeNode);
const schemaType = this._schema.getType(innerType.name.value);
const isArray = typeNode.kind === Kind.LIST_TYPE ||
(typeNode.kind === Kind.NON_NULL_TYPE && typeNode.type.kind === Kind.LIST_TYPE);
let result;
if (isScalarType(schemaType)) {
if (this.scalars[schemaType.name]) {
result = {
baseType: this.scalars[schemaType.name],
typeName: this.scalars[schemaType.name],
isScalar: true,
isEnum: false,
isArray,
};
}
else {
result = { isArray, baseType: 'Object', typeName: 'Object', isScalar: true, isEnum: false };
}
}
else if (isInputObjectType(schemaType)) {
const convertedName = this.convertName(schemaType.name);
const typeName = convertedName.endsWith('Input') ? convertedName : `${convertedName}Input`;
result = {
baseType: typeName,
typeName,
isScalar: false,
isEnum: false,
isArray,
};
}
else if (isEnumType(schemaType)) {
result = {
isArray,
baseType: this.convertName(schemaType.name),
typeName: this.convertName(schemaType.name),
isScalar: false,
isEnum: true,
};
}
else {
result = { isArray, baseType: 'Object', typeName: 'Object', isScalar: true, isEnum: false };
}
if (result) {
result.typeName = wrapTypeWithModifiers(result.typeName, typeNode, this.config.listType);
}
return result;
}
buildInputTransfomer(name, inputValueArray) {
this._addMapImport = true;
const classMembers = inputValueArray
.map(arg => {
const typeToUse = this.resolveInputFieldType(arg.type);
if (arg.name.value === 'interface' || arg.name.value === 'new') {
// forcing prefix of _ since interface is a keyword in JAVA
return indent(`private ${typeToUse.typeName} _${this.config.classMembersPrefix}${arg.name.value};`);
}
return indent(`private ${typeToUse.typeName} ${this.config.classMembersPrefix}${arg.name.value};`);
})
.join('\n');
const ctorSet = inputValueArray
.map(arg => {
const typeToUse = this.resolveInputFieldType(arg.type);
if (typeToUse.isArray && !typeToUse.isScalar) {
this._addListImport = true;
if (typeToUse.isEnum) {
return indentMultiline(`if (args.get("${arg.name.value}") != null) {
this.${this.config.classMembersPrefix}${arg.name.value} = ((List<Object>) args.get("${arg.name.value}")).stream()
.map(item -> item instanceof ${typeToUse.baseType} ? item : ${typeToUse.baseType}.valueOf((String) item))
.map(${typeToUse.baseType}.class::cast)
.collect(Collectors.toList());
}`, 3);
}
return indentMultiline(`if (args.get("${arg.name.value}") != null) {
this.${arg.name.value} = (${this.config.listType}<${typeToUse.baseType}>) args.get("${arg.name.value}");
}`, 3);
}
if (typeToUse.isScalar) {
return indent(`this.${this.config.classMembersPrefix}${arg.name.value} = (${typeToUse.typeName}) args.get("${arg.name.value}");`, 3);
}
if (typeToUse.isEnum) {
return indentMultiline(`if (args.get("${arg.name.value}") instanceof ${typeToUse.typeName}) {
this.${this.config.classMembersPrefix}${arg.name.value} = (${typeToUse.typeName}) args.get("${arg.name.value}");
} else {
this.${this.config.classMembersPrefix}${arg.name.value} = ${typeToUse.typeName}.valueOf((String) args.get("${arg.name.value}"));
}`, 3);
}
if (arg.name.value === 'interface') {
// forcing prefix of _ since interface is a keyword in JAVA
return indent(`this._${this.config.classMembersPrefix}${arg.name.value} = new ${typeToUse.typeName}((Map<String, Object>) args.get("${arg.name.value}"));`, 3);
}
return indent(`this.${this.config.classMembersPrefix}${arg.name.value} = new ${typeToUse.typeName}((Map<String, Object>) args.get("${arg.name.value}"));`, 3);
})
.join('\n');
const getters = inputValueArray
.map(arg => {
const typeToUse = this.resolveInputFieldType(arg.type);
if (arg.name.value === 'interface' || arg.name.value === 'new') {
// forcing prefix of _ since interface is a keyword in JAVA
return indent(`public ${typeToUse.typeName} get${this.convertName(arg.name.value)}() { return this._${this.config.classMembersPrefix}${arg.name.value}; }`);
}
return indent(`public ${typeToUse.typeName} get${this.convertName(arg.name.value)}() { return this.${this.config.classMembersPrefix}${arg.name.value}; }`);
})
.join('\n');
const setters = inputValueArray
.map(arg => {
const typeToUse = this.resolveInputFieldType(arg.type);
if (arg.name.value === 'interface' || arg.name.value === 'new') {
return indent(`public void set${this.convertName(arg.name.value)}(${typeToUse.typeName} _${arg.name.value}) { this._${arg.name.value} = _${arg.name.value}; }`);
}
return indent(`public void set${this.convertName(arg.name.value)}(${typeToUse.typeName} ${arg.name.value}) { this.${arg.name.value} = ${arg.name.value}; }`);
})
.join('\n');
if (this.config.useEmptyCtor) {
return `public static class ${name} {
${classMembers}
public ${name}() {}
${getters}
${setters}
}`;
}
return `public static class ${name} {
${classMembers}
public ${name}(Map<String, Object> args) {
if (args != null) {
${ctorSet}
}
}
${getters}
${setters}
}`;
}
FieldDefinition(node) {
return (typeName) => {
if (node.arguments.length > 0) {
const transformerName = `${this.convertName(typeName, {
useTypesPrefix: true,
})}${this.convertName(node.name.value, { useTypesPrefix: false })}Args`;
return this.buildInputTransfomer(transformerName, node.arguments);
}
return null;
};
}
InputObjectTypeDefinition(node) {
const convertedName = this.convertName(node);
const name = convertedName.endsWith('Input') ? convertedName : `${convertedName}Input`;
return this.buildInputTransfomer(name, node.fields);
}
ObjectTypeDefinition(node) {
const fieldsArguments = node.fields.map(f => f(node.name.value)).filter(r => r);
return fieldsArguments.join('\n');
}
}