2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.java.api.generator
10 import static extension org.apache.commons.text.StringEscapeUtils.escapeJava;
12 import com.google.common.base.MoreObjects
13 import com.google.common.collect.ImmutableMap
14 import com.google.common.collect.ImmutableSortedSet
15 import com.google.common.collect.ImmutableList
16 import java.util.ArrayList
17 import java.util.Arrays
18 import java.util.Collection
19 import java.util.Collections
20 import java.util.HashMap
21 import java.util.HashSet
22 import java.util.LinkedHashSet
25 import java.util.Objects
27 import java.util.regex.Pattern
28 import org.opendaylight.mdsal.binding.model.api.ConcreteType
29 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
30 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
31 import org.opendaylight.mdsal.binding.model.api.GeneratedType
32 import org.opendaylight.mdsal.binding.model.api.JavaTypeName
33 import org.opendaylight.mdsal.binding.model.api.MethodSignature
34 import org.opendaylight.mdsal.binding.model.api.Type
35 import org.opendaylight.mdsal.binding.model.api.ParameterizedType
36 import org.opendaylight.mdsal.binding.model.api.Restrictions
37 import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl
38 import org.opendaylight.mdsal.binding.model.util.Types
39 import org.opendaylight.mdsal.binding.model.util.generated.type.builder.CodegenGeneratedTOBuilder
40 import org.opendaylight.mdsal.binding.model.util.TypeConstants
41 import org.opendaylight.yangtools.concepts.Builder
42 import org.opendaylight.yangtools.yang.binding.Augmentable
43 import org.opendaylight.yangtools.yang.binding.AugmentationHolder
44 import org.opendaylight.yangtools.yang.binding.CodeHelpers
45 import org.opendaylight.yangtools.yang.binding.DataObject
46 import org.opendaylight.yangtools.yang.binding.Identifiable
49 * Template for generating JAVA builder classes.
52 class BuilderTemplate extends BaseTemplate {
55 * Constant with the name of the concrete method.
57 val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"
60 * Constant with the suffix for builder classes.
62 val static BUILDER = 'Builder'
65 * Constant with the name of the BuilderFor interface
67 val static BUILDERFOR = Builder.simpleName;
70 * Constant with suffix for the classes which are generated from the builder classes.
72 val static IMPL = 'Impl'
75 * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME
77 var GeneratedProperty augmentField
80 * Set of class attributes (fields) which are derived from the getter methods names
82 val Set<GeneratedProperty> properties
84 private static val METHOD_COMPARATOR = new AlphabeticallyTypeMemberComparator<MethodSignature>();
87 * Constructs new instance of this class.
88 * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
90 new(GeneratedType genType) {
92 this.properties = propertiesFromMethods(createMethods)
97 * Returns set of method signature instances which contains all the methods of the <code>genType</code>
98 * and all the methods of the implemented interfaces.
100 * @returns set of method signature instances
102 def private Set<MethodSignature> createMethods() {
103 val Set<MethodSignature> methods = new LinkedHashSet();
104 methods.addAll(type.methodDefinitions)
105 collectImplementedMethods(methods, type.implements)
106 val Set<MethodSignature> sortedMethods = ImmutableSortedSet.orderedBy(METHOD_COMPARATOR).addAll(methods).build()
112 * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code>
113 * and recursively their implemented interfaces.
115 * @param methods set of method signatures
116 * @param implementedIfcs list of implemented interfaces
118 def private void collectImplementedMethods(Set<MethodSignature> methods, List<Type> implementedIfcs) {
119 if (implementedIfcs === null || implementedIfcs.empty) {
122 for (implementedIfc : implementedIfcs) {
123 if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {
124 val ifc = implementedIfc as GeneratedType
125 methods.addAll(ifc.methodDefinitions)
126 collectImplementedMethods(methods, ifc.implements)
127 } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {
128 for (m : Augmentable.methods) {
129 if (m.name == GET_AUGMENTATION_METHOD_NAME) {
130 val identifier = JavaTypeName.create(m.returnType)
131 val tmpGenTO = new CodegenGeneratedTOBuilder(identifier)
132 val refType = new ReferencedTypeImpl(identifier)
133 val generic = new ReferencedTypeImpl(type.identifier)
134 val parametrizedReturnType = Types.parameterizedTypeFor(refType, generic)
135 tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)
136 augmentField = tmpGenTO.build.methodDefinitions.first.propertyFromGetter
144 * Returns the first element of the list <code>elements</code>.
146 * @param list of elements
148 def private <E> first(List<E> elements) {
153 * Creates set of generated property instances from getter <code>methods</code>.
155 * @param set of method signature instances which should be transformed to list of properties
156 * @return set of generated property instances which represents the getter <code>methods</code>
158 def private propertiesFromMethods(Collection<MethodSignature> methods) {
159 if (methods === null || methods.isEmpty()) {
160 return Collections.emptySet
162 val Set<GeneratedProperty> result = new LinkedHashSet
164 val createdField = m.propertyFromGetter
165 if (createdField !== null) {
166 result.add(createdField)
173 * Creates generated property instance from the getter <code>method</code> name and return type.
175 * @param method method signature from which is the method name and return type obtained
176 * @return generated property instance for the getter <code>method</code>
177 * @throws IllegalArgumentException<ul>
178 * <li>if the <code>method</code> equals <code>null</code></li>
179 * <li>if the name of the <code>method</code> equals <code>null</code></li>
180 * <li>if the name of the <code>method</code> is empty</li>
181 * <li>if the return type of the <code>method</code> equals <code>null</code></li>
184 def private GeneratedProperty propertyFromGetter(MethodSignature method) {
185 if (method === null || method.name === null || method.name.empty || method.returnType === null) {
186 throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")
189 if (Types.BOOLEAN.equals(method.returnType)) {
192 if (method.name.startsWith(prefix)) {
193 val fieldName = method.getName().substring(prefix.length()).toFirstLower
194 val tmpGenTO = new CodegenGeneratedTOBuilder(JavaTypeName.create("foo", "foo"))
195 tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)
196 return tmpGenTO.build.properties.first
200 override isLocalInnerClass(JavaTypeName name) {
201 // Builders do not have inner types
206 * Template method which generates JAVA class body for builder class and for IMPL class.
208 * @return string with JAVA source code
211 «wrapToDocumentation(formatDataForJavaDoc(type))»
212 public class «type.name»«BUILDER» implements «BUILDERFOR»<«type.importedName»> {
214 «generateFields(false)»
216 «constantsDeclarations()»
218 «generateAugmentField(false)»
220 «generateConstructorsFromIfcs(type)»
222 «generateCopyConstructor(false)»
224 «generateMethodFieldsFrom(type)»
226 «generateGetters(false)»
231 public «type.name» build() {
232 return new «type.name»«IMPL»(this);
235 private static final class «type.name»«IMPL» implements «type.name» {
237 «implementedInterfaceGetter»
239 «generateFields(true)»
241 «generateAugmentField(true)»
243 «generateCopyConstructor(true)»
245 «generateGetters(true)»
251 «generateToString(properties)»
258 * Generate default constructor and constructor for every implemented interface from uses statements.
260 def private generateConstructorsFromIfcs(Type type) '''
261 public «type.name»«BUILDER»() {
263 «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»
264 «val ifc = type as GeneratedType»
265 «FOR impl : ifc.implements»
266 «generateConstructorFromIfc(impl)»
272 * Generate constructor with argument of given type.
274 def private Object generateConstructorFromIfc(Type impl) '''
275 «IF (impl instanceof GeneratedType)»
276 «IF !(impl.methodDefinitions.empty)»
277 public «type.name»«BUILDER»(«impl.fullyQualifiedName» arg) {
278 «printConstructorPropertySetter(impl)»
281 «FOR implTypeImplement : impl.implements»
282 «generateConstructorFromIfc(implTypeImplement)»
287 def private Object printConstructorPropertySetter(Type implementedIfc) '''
288 «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
289 «val ifc = implementedIfc as GeneratedType»
290 «FOR getter : ifc.methodDefinitions»
291 this._«getter.propertyNameFromGetter» = arg.«getter.name»();
293 «FOR impl : ifc.implements»
294 «printConstructorPropertySetter(impl)»
300 * Generate 'fieldsFrom' method to set builder properties based on type of given argument.
302 def private generateMethodFieldsFrom(Type type) '''
303 «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»
304 «val ifc = type as GeneratedType»
305 «IF ifc.hasImplementsFromUses»
306 «val List<Type> done = ifc.getBaseIfcs»
307 «generateMethodFieldsFromComment(ifc)»
308 public void fieldsFrom(«DataObject.importedName» arg) {
309 boolean isValidArg = false;
310 «FOR impl : ifc.getAllIfcs»
311 «generateIfCheck(impl, done)»
313 «CodeHelpers.importedName».validValue(isValidArg, arg, "«ifc.getAllIfcs.toListOfNames»");
319 def private generateMethodFieldsFromComment(GeneratedType type) '''
321 * Set fields from given grouping argument. Valid argument is instance of one of following types:
323 «FOR impl : type.getAllIfcs»
324 * <li>«impl.fullyQualifiedName»</li>
328 * @param arg grouping object
329 * @throws IllegalArgumentException if given argument is none of valid types
334 * Method is used to find out if given type implements any interface from uses.
336 def boolean hasImplementsFromUses(GeneratedType type) {
338 for (impl : type.getAllIfcs) {
339 if ((impl instanceof GeneratedType) && !((impl as GeneratedType).methodDefinitions.empty)) {
346 def private generateIfCheck(Type impl, List<Type> done) '''
347 «IF (impl instanceof GeneratedType) && !((impl as GeneratedType).methodDefinitions.empty)»
348 «val implType = impl as GeneratedType»
349 if (arg instanceof «implType.fullyQualifiedName») {
350 «printPropertySetter(implType)»
356 def private printPropertySetter(Type implementedIfc) '''
357 «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
358 «val ifc = implementedIfc as GeneratedType»
359 «FOR getter : ifc.methodDefinitions»
360 this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();
365 private def List<Type> getBaseIfcs(GeneratedType type) {
366 val List<Type> baseIfcs = new ArrayList();
367 for (ifc : type.implements) {
368 if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) {
375 private def Set<Type> getAllIfcs(Type type) {
376 val Set<Type> baseIfcs = new HashSet()
377 if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
378 val ifc = type as GeneratedType
379 for (impl : ifc.implements) {
380 if (impl instanceof GeneratedType && !(impl as GeneratedType).methodDefinitions.empty) {
383 baseIfcs.addAll(impl.getAllIfcs)
389 private def List<String> toListOfNames(Collection<Type> types) {
390 val List<String> names = new ArrayList
392 names.add(type.fullyQualifiedName)
398 * Template method which generates class attributes.
400 * @param boolean value which specify whether field is|isn't final
401 * @return string with class attributes and their types
403 def private generateFields(boolean _final) '''
404 «IF properties !== null»
406 private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
411 def private generateAugmentField(boolean isPrivate) '''
412 «IF augmentField !== null»
413 «IF isPrivate»private «ENDIF»«Map.importedName»<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = «Collections.importedName».emptyMap();
417 def private constantsDeclarations() '''
418 «FOR c : type.getConstantDefinitions»
419 «IF c.getName.startsWith(TypeConstants.PATTERN_CONSTANT_NAME)»
420 «val cValue = c.value as Map<String, String>»
421 «val String fieldSuffix = c.getName.substring(TypeConstants.PATTERN_CONSTANT_NAME.length).toLowerCase»
422 public static final «List.importedName»<String> «c.getName» = «ImmutableList.importedName».of(
423 «FOR v : cValue.keySet SEPARATOR ", "»"«v.escapeJava»"«ENDFOR»);
424 «IF cValue.size == 1»
425 private static final «Pattern.importedName» «Constants.MEMBER_PATTERN_LIST»«fieldSuffix» = «Pattern.importedName».compile(«c.getName».get(0));
426 private static final String «Constants.MEMBER_REGEX_LIST»«fieldSuffix» = "«cValue.values.get(0).escapeJava»";
428 private static final «Pattern.importedName»[] «Constants.MEMBER_PATTERN_LIST»«fieldSuffix» = «CodeHelpers.importedName».compilePatterns(«c.getName»);
429 private static final String[] «Constants.MEMBER_REGEX_LIST»«fieldSuffix» = { «
430 FOR v : cValue.values SEPARATOR ", "»"«v.escapeJava»"«ENDFOR» };
438 def private generateCheckers(GeneratedProperty field, Restrictions restrictions, Type actualType) '''
439 «IF restrictions.rangeConstraint.present»
440 «AbstractRangeGenerator.forType(actualType).generateRangeChecker(field.name.toFirstUpper,
441 restrictions.rangeConstraint.get, this)»
443 «IF restrictions.lengthConstraint.present»
444 «LengthGenerator.generateLengthChecker(field.fieldName.toString, actualType, restrictions.lengthConstraint.get, this)»
448 def private checkArgument(GeneratedProperty property, Restrictions restrictions, Type actualType) '''
449 «IF restrictions.getRangeConstraint.isPresent»
450 «IF actualType instanceof ConcreteType»
451 «AbstractRangeGenerator.forType(actualType).generateRangeCheckerCall(property.getName.toFirstUpper, "value")»
453 «AbstractRangeGenerator.forType(actualType).generateRangeCheckerCall(property.getName.toFirstUpper, "value.getValue()")»
456 «IF restrictions.getLengthConstraint.isPresent»
457 «IF actualType instanceof ConcreteType»
458 «LengthGenerator.generateLengthCheckerCall(property.fieldName.toString, "value")»
460 «LengthGenerator.generateLengthCheckerCall(property.fieldName.toString, "value.getValue()")»
464 «val fieldUpperCase = property.fieldName.toString.toUpperCase()»
465 «FOR currentConstant : type.getConstantDefinitions»
466 «IF currentConstant.getName.startsWith(TypeConstants.PATTERN_CONSTANT_NAME)
467 && fieldUpperCase.equals(currentConstant.getName.substring(TypeConstants.PATTERN_CONSTANT_NAME.length))»
468 «CodeHelpers.importedName».checkPattern(value, «Constants.MEMBER_PATTERN_LIST»«property.fieldName», «Constants.MEMBER_REGEX_LIST»«property.fieldName»);
473 def private Restrictions restrictionsForSetter(Type actualType) {
474 if (actualType instanceof GeneratedType) {
477 return actualType.restrictions;
480 def private generateListSetter(GeneratedProperty field, Type actualType) '''
481 «val restrictions = restrictionsForSetter(actualType)»
482 «IF restrictions !== null»
483 «generateCheckers(field, restrictions, actualType)»
485 public «type.getName»Builder set«field.getName.toFirstUpper»(final «field.returnType.importedName» values) {
486 «IF restrictions !== null»
487 if (values != null) {
488 for («actualType.getFullyQualifiedName» value : values) {
489 «checkArgument(field, restrictions, actualType)»
493 this.«field.fieldName.toString» = values;
499 def private generateSetter(GeneratedProperty field, Type actualType) '''
500 «val restrictions = restrictionsForSetter(actualType)»
501 «IF restrictions !== null»
502 «generateCheckers(field, restrictions, actualType)»
505 public «type.getName»Builder set«field.getName.toFirstUpper»(final «field.returnType.importedName» value) {
506 «IF restrictions !== null»
508 «checkArgument(field, restrictions, actualType)»
511 this.«field.fieldName.toString» = value;
516 private def Type getActualType(ParameterizedType ptype) {
517 return ptype.getActualTypeArguments.get(0)
521 * Template method which generates setter methods
523 * @return string with the setter methods
525 def private generateSetters() '''
526 «FOR property : properties»
527 «IF property.returnType instanceof ParameterizedType
528 && (property.returnType as ParameterizedType).rawType.equals(Types.LIST_TYPE)»
529 «generateListSetter(property, getActualType(property.returnType as ParameterizedType))»
531 «generateSetter(property, property.returnType)»
535 «IF augmentField !== null»
536 public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(«Class.importedName»<? extends «augmentField.returnType.importedName»> augmentationType, «augmentField.returnType.importedName» augmentationValue) {
537 if (augmentationValue == null) {
538 return remove«augmentField.name.toFirstUpper»(augmentationType);
541 if (!(this.«augmentField.name» instanceof «HashMap.importedName»)) {
542 this.«augmentField.name» = new «HashMap.importedName»<>();
545 this.«augmentField.name».put(augmentationType, augmentationValue);
549 public «type.name»«BUILDER» remove«augmentField.name.toFirstUpper»(«Class.importedName»<? extends «augmentField.returnType.importedName»> augmentationType) {
550 if (this.«augmentField.name» instanceof «HashMap.importedName») {
551 this.«augmentField.name».remove(augmentationType);
558 def private CharSequence generateCopyConstructor(boolean impl) '''
559 «IF impl»private«ELSE»public«ENDIF» «type.name»«IF impl»«IMPL»«ELSE»«BUILDER»«ENDIF»(«type.name»«IF impl»«BUILDER»«ENDIF» base) {
560 «val allProps = new ArrayList(properties)»
561 «val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))»
562 «val keyType = type.getKey»
563 «IF isList && keyType !== null»
564 «val keyProps = new ArrayList((keyType as GeneratedTransferObject).properties)»
565 «Collections.sort(keyProps,
567 return p1.name.compareTo(p2.name)
570 «FOR field : keyProps»
571 «removeProperty(allProps, field.name)»
573 «removeProperty(allProps, "key")»
574 if (base.getKey() == null) {
575 this._key = new «keyType.importedName»(
576 «FOR keyProp : keyProps SEPARATOR ", "»
577 base.«keyProp.getterMethodName»()
580 «FOR field : keyProps»
581 this.«field.fieldName» = base.«field.getterMethodName»();
584 this._key = base.getKey();
585 «FOR field : keyProps»
586 this.«field.fieldName» = _key.«field.getterMethodName»();
590 «FOR field : allProps»
591 this.«field.fieldName» = base.«field.getterMethodName»();
593 «IF augmentField !== null»
595 this.«augmentField.name» = «ImmutableMap.importedName».copyOf(base.«augmentField.name»);
597 if (base instanceof «type.name»«IMPL») {
598 «type.name»«IMPL» impl = («type.name»«IMPL») base;
599 if (!impl.«augmentField.name».isEmpty()) {
600 this.«augmentField.name» = new «HashMap.importedName»<>(impl.«augmentField.name»);
602 } else if (base instanceof «AugmentationHolder.importedName») {
603 @SuppressWarnings("unchecked")
604 «AugmentationHolder.importedName»<«type.importedName»> casted =(«AugmentationHolder.importedName»<«type.importedName»>) base;
605 if (!casted.augmentations().isEmpty()) {
606 this.«augmentField.name» = new «HashMap.importedName»<>(casted.augmentations());
614 private def boolean implementsIfc(GeneratedType type, Type impl) {
615 for (Type ifc : type.implements) {
616 if (ifc.equals(impl)) {
623 private def Type getKey(GeneratedType type) {
624 for (m : type.methodDefinitions) {
625 if ("getKey".equals(m.name)) {
632 private def void removeProperty(Collection<GeneratedProperty> props, String name) {
633 var GeneratedProperty toRemove = null
635 if (p.name.equals(name)) {
639 if (toRemove !== null) {
640 props.remove(toRemove);
645 * Template method which generate getter methods for IMPL class.
647 * @return string with getter methods
649 def private generateGetters(boolean addOverride) '''
650 «IF !properties.empty»
651 «FOR field : properties SEPARATOR '\n'»
652 «IF addOverride»@Override«ENDIF»
656 «IF augmentField !== null»
658 @SuppressWarnings("unchecked")
659 «IF addOverride»@Override«ENDIF»
660 public <E extends «augmentField.returnType.importedName»> E get«augmentField.name.toFirstUpper»(«Class.importedName»<E> augmentationType) {
661 return (E) «augmentField.name».get(«CodeHelpers.importedName».nonNullValue(augmentationType, "augmentationType"));
667 * Template method which generates the method <code>hashCode()</code>.
669 * @return string with the <code>hashCode()</code> method definition in JAVA format
671 def protected generateHashCode() '''
672 «IF !properties.empty || augmentField !== null»
673 private int hash = 0;
674 private volatile boolean hashValid = false;
677 public int hashCode() {
682 final int prime = 31;
684 «FOR property : properties»
685 «IF property.returnType.name.contains("[")»
686 result = prime * result + «Arrays.importedName».hashCode(«property.fieldName»);
688 result = prime * result + «Objects.importedName».hashCode(«property.fieldName»);
691 «IF augmentField !== null»
692 result = prime * result + «Objects.importedName».hashCode(«augmentField.name»);
703 * Template method which generates the method <code>equals()</code>.
705 * @return string with the <code>equals()</code> method definition in JAVA format
707 def protected generateEquals() '''
708 «IF !properties.empty || augmentField !== null»
710 public boolean equals(«Object.importedName» obj) {
714 if (!(obj instanceof «DataObject.importedName»)) {
717 if (!«type.importedName».class.equals(((«DataObject.importedName»)obj).getImplementedInterface())) {
720 «type.importedName» other = («type.importedName»)obj;
721 «FOR property : properties»
722 «val fieldName = property.fieldName»
723 «IF property.returnType.name.contains("[")»
724 if (!«Arrays.importedName».equals(«fieldName», other.«property.getterMethodName»())) {
726 if (!«Objects.importedName».equals(«fieldName», other.«property.getterMethodName»())) {
731 «IF augmentField !== null»
732 if (getClass() == obj.getClass()) {
733 // Simple case: we are comparing against self
734 «type.name»«IMPL» otherImpl = («type.name»«IMPL») obj;
735 «val fieldName = augmentField.name»
736 if (!«Objects.importedName».equals(«fieldName», otherImpl.«fieldName»)) {
740 // Hard case: compare our augments with presence there...
741 for («Map.importedName».Entry<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e : «augmentField.name».entrySet()) {
742 if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
746 // .. and give the other one the chance to do the same
747 if (!obj.equals(this)) {
757 def override generateToString(Collection<GeneratedProperty> properties) '''
758 «IF properties !== null»
760 public «String.importedName» toString() {
761 final «MoreObjects.importedName».ToStringHelper helper = «MoreObjects.importedName».toStringHelper("«type.name»");
762 «FOR property : properties»
763 «CodeHelpers.importedName».appendValue(helper, "«property.fieldName»", «property.fieldName»);
765 «IF augmentField !== null»
766 «CodeHelpers.importedName».appendValue(helper, "«augmentField.name»", «augmentField.name».values());
768 return helper.toString();
773 def implementedInterfaceGetter() '''
775 public «Class.importedName»<«type.importedName»> getImplementedInterface() {
776 return «type.importedName».class;
780 private def createDescription(GeneratedType type) {
782 Class that builds {@link «type.importedName»} instances.
784 @see «type.importedName»
788 override def protected String formatDataForJavaDoc(GeneratedType type) {
789 val typeDescription = createDescription(type)
792 «IF !typeDescription.nullOrEmpty»