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.yangtools.sal.java.api.generator
10 import com.google.common.collect.ImmutableSortedSet
11 import com.google.common.collect.Range
12 import java.util.ArrayList
13 import java.util.Arrays
14 import java.util.Collection
15 import java.util.Collections
16 import java.util.HashMap
17 import java.util.HashSet
18 import java.util.LinkedHashSet
22 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
23 import org.opendaylight.yangtools.binding.generator.util.Types
24 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl
25 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType
26 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
27 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
28 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
29 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
30 import org.opendaylight.yangtools.sal.binding.model.api.Type
31 import org.opendaylight.yangtools.yang.binding.Augmentable
32 import org.opendaylight.yangtools.yang.binding.ChildOf
33 import org.opendaylight.yangtools.yang.binding.DataObject
34 import org.opendaylight.yangtools.yang.binding.Identifiable
37 * Template for generating JAVA builder classes.
40 class BuilderTemplate extends BaseTemplate {
43 * Constant with the name of the concrete method.
45 val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"
48 * Constant with the suffix for builder classes.
50 val static BUILDER = 'Builder'
53 * Constant with suffix for the classes which are generated from the builder classes.
55 val static IMPL = 'Impl'
58 * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME
60 var GeneratedProperty augmentField
63 * Set of class attributes (fields) which are derived from the getter methods names
65 val Set<GeneratedProperty> properties
67 private static val METHOD_COMPARATOR = new AlphabeticallyTypeMemberComparator<MethodSignature>();
70 * Constructs new instance of this class.
71 * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
73 new(GeneratedType genType) {
75 this.properties = propertiesFromMethods(createMethods)
79 * Returns set of method signature instances which contains all the methods of the <code>genType</code>
80 * and all the methods of the implemented interfaces.
82 * @returns set of method signature instances
84 def private Set<MethodSignature> createMethods() {
85 val Set<MethodSignature> methods = new LinkedHashSet();
86 methods.addAll(type.methodDefinitions)
87 collectImplementedMethods(methods, type.implements)
88 val Set<MethodSignature> sortedMethods = ImmutableSortedSet.orderedBy(METHOD_COMPARATOR).addAll(methods).build()
94 * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code>
95 * and recursively their implemented interfaces.
97 * @param methods set of method signatures
98 * @param implementedIfcs list of implemented interfaces
100 def private void collectImplementedMethods(Set<MethodSignature> methods, List<Type> implementedIfcs) {
101 if (implementedIfcs == null || implementedIfcs.empty) {
104 for (implementedIfc : implementedIfcs) {
105 if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {
106 val ifc = implementedIfc as GeneratedType
107 methods.addAll(ifc.methodDefinitions)
108 collectImplementedMethods(methods, ifc.implements)
109 } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {
110 for (m : Augmentable.methods) {
111 if (m.name == GET_AUGMENTATION_METHOD_NAME) {
112 val fullyQualifiedName = m.returnType.name
113 val pkg = fullyQualifiedName.package
114 val name = fullyQualifiedName.name
115 val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name)
116 val refType = new ReferencedTypeImpl(pkg, name)
117 val generic = new ReferencedTypeImpl(type.packageName, type.name)
118 val parametrizedReturnType = Types.parameterizedTypeFor(refType, generic)
119 tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)
120 augmentField = tmpGenTO.toInstance.methodDefinitions.first.propertyFromGetter
128 * Returns the first element of the list <code>elements</code>.
130 * @param list of elements
132 def private <E> first(List<E> elements) {
137 * Returns the name of the package from <code>fullyQualifiedName</code>.
139 * @param fullyQualifiedName string with fully qualified type name (package + type)
140 * @return string with the package name
142 def private String getPackage(String fullyQualifiedName) {
143 val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
144 return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)
148 * Returns the name of tye type from <code>fullyQualifiedName</code>
150 * @param fullyQualifiedName string with fully qualified type name (package + type)
151 * @return string with the name of the type
153 def private String getName(String fullyQualifiedName) {
154 val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
155 return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)
159 * Creates set of generated property instances from getter <code>methods</code>.
161 * @param set of method signature instances which should be transformed to list of properties
162 * @return set of generated property instances which represents the getter <code>methods</code>
164 def private propertiesFromMethods(Collection<MethodSignature> methods) {
165 if (methods == null || methods.isEmpty()) {
166 return Collections.emptySet
168 val Set<GeneratedProperty> result = new LinkedHashSet
170 val createdField = m.propertyFromGetter
171 if (createdField != null) {
172 result.add(createdField)
179 * Creates generated property instance from the getter <code>method</code> name and return type.
181 * @param method method signature from which is the method name and return type obtained
182 * @return generated property instance for the getter <code>method</code>
183 * @throws IllegalArgumentException<ul>
184 * <li>if the <code>method</code> equals <code>null</code></li>
185 * <li>if the name of the <code>method</code> equals <code>null</code></li>
186 * <li>if the name of the <code>method</code> is empty</li>
187 * <li>if the return type of the <code>method</code> equals <code>null</code></li>
190 def private GeneratedProperty propertyFromGetter(MethodSignature method) {
191 if (method == null || method.name == null || method.name.empty || method.returnType == null) {
192 throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")
195 if(Types.BOOLEAN.equals(method.returnType)) {
198 if (method.name.startsWith(prefix)) {
199 val fieldName = method.getName().substring(prefix.length()).toFirstLower
200 val tmpGenTO = new GeneratedTOBuilderImpl("foo", "foo")
201 tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)
202 return tmpGenTO.toInstance.properties.first
207 * Template method which generates JAVA class body for builder class and for IMPL class.
209 * @return string with JAVA source code
212 «wrapToDocumentation(formatDataForJavaDoc(type))»
213 public class «type.name»«BUILDER» {
215 «generateFields(false)»
217 «generateAugmentField(false)»
219 «generateConstructorsFromIfcs(type)»
221 «generateCopyConstructor(false)»
223 «generateMethodFieldsFrom(type)»
225 «generateGetters(false)»
229 «generateBuildMethod»
231 «generateBuildBoxedMethod»
233 private static final class «type.name»«IMPL» implements «type.name» {
235 «implementedInterfaceGetter»
237 «generateFields(true)»
239 «generateAugmentField(true)»
241 «generateCopyConstructor(true)»
243 «generateGetters(true)»
249 «generateToString(properties)»
255 def private generateBuildMethod() '''
256 public «type.name» build() {
257 return new «type.name»«IMPL»(this);
261 def private generateBuildBoxedMethod() {
262 if(type.suitableForBoxing && type.parentType != null && isContainerAndIsNotList(type)) {
263 val parentTypeBuilder = createParentTypeBuilder()
264 if (countMatches(parentTypeBuilder, "org") < 2) {
266 public «type.parentType.importedName» buildBoxed() {
267 return new «parentTypeBuilder»().set«type.name»(build()).build();
275 def private int countMatches(String string, String subString) {
276 if (string.nullOrEmpty || subString.nullOrEmpty) {
281 while ((idx = string.indexOf(subString, idx)) != -1) {
283 idx = idx + subString.length();
288 def private createParentTypeBuilder() {
289 return type.parentType.packageName + "." + type.parentType.importedName + "Builder"
292 def private boolean isContainerAndIsNotList(GeneratedType type) {
293 val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))
294 val implementsChildOf = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(ChildOf), type))
296 if (implementsChildOf && !isList) {
303 * Generate default constructor and constructor for every implemented interface from uses statements.
305 def private generateConstructorsFromIfcs(Type type) '''
306 public «type.name»«BUILDER»() {
308 «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»
309 «val ifc = type as GeneratedType»
310 «FOR impl : ifc.implements»
311 «generateConstructorFromIfc(impl)»
317 * Generate constructor with argument of given type.
319 def private Object generateConstructorFromIfc(Type impl) '''
320 «IF (impl instanceof GeneratedType)»
321 «val implType = impl as GeneratedType»
323 «IF !(implType.methodDefinitions.empty)»
324 public «type.name»«BUILDER»(«implType.fullyQualifiedName» arg) {
325 «printConstructorPropertySetter(implType)»
328 «FOR implTypeImplement : implType.implements»
329 «generateConstructorFromIfc(implTypeImplement)»
334 def private Object printConstructorPropertySetter(Type implementedIfc) '''
335 «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
336 «val ifc = implementedIfc as GeneratedType»
337 «FOR getter : ifc.methodDefinitions»
338 this._«getter.propertyNameFromGetter» = arg.«getter.name»();
340 «FOR impl : ifc.implements»
341 «printConstructorPropertySetter(impl)»
347 * Generate 'fieldsFrom' method to set builder properties based on type of given argument.
349 def private generateMethodFieldsFrom(Type type) '''
350 «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»
351 «val ifc = type as GeneratedType»
352 «IF ifc.hasImplementsFromUses»
353 «val List<Type> done = ifc.getBaseIfcs»
354 «generateMethodFieldsFromComment(ifc)»
355 public void fieldsFrom(«DataObject.importedName» arg) {
356 boolean isValidArg = false;
357 «FOR impl : ifc.getAllIfcs»
358 «generateIfCheck(impl, done)»
361 throw new IllegalArgumentException(
362 "expected one of: «ifc.getAllIfcs.toListOfNames» \n" +
371 def private generateMethodFieldsFromComment(GeneratedType type) '''
373 *Set fields from given grouping argument. Valid argument is instance of one of following types:
375 «FOR impl : type.getAllIfcs»
376 * <li>«impl.fullyQualifiedName»</li>
380 * @param arg grouping object
381 * @throws IllegalArgumentException if given argument is none of valid types
386 * Method is used to find out if given type implements any interface from uses.
388 def boolean hasImplementsFromUses(GeneratedType type) {
390 for (impl : type.getAllIfcs) {
391 if ((impl instanceof GeneratedType) && !((impl as GeneratedType).methodDefinitions.empty)) {
398 def private generateIfCheck(Type impl, List<Type> done) '''
399 «IF (impl instanceof GeneratedType) && !((impl as GeneratedType).methodDefinitions.empty)»
400 «val implType = impl as GeneratedType»
401 if (arg instanceof «implType.fullyQualifiedName») {
402 «printPropertySetter(implType)»
408 def private printPropertySetter(Type implementedIfc) '''
409 «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
410 «val ifc = implementedIfc as GeneratedType»
411 «FOR getter : ifc.methodDefinitions»
412 this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();
417 private def List<Type> getBaseIfcs(GeneratedType type) {
418 val List<Type> baseIfcs = new ArrayList();
419 for (ifc : type.implements) {
420 if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) {
427 private def Set<Type> getAllIfcs(Type type) {
428 val Set<Type> baseIfcs = new HashSet()
429 if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
430 val ifc = type as GeneratedType
431 for (impl : ifc.implements) {
432 if (impl instanceof GeneratedType && !(impl as GeneratedType).methodDefinitions.empty) {
435 baseIfcs.addAll(impl.getAllIfcs)
441 private def List<String> toListOfNames(Collection<Type> types) {
442 val List<String> names = new ArrayList
444 names.add(type.fullyQualifiedName)
450 * Template method which generates class attributes.
452 * @param boolean value which specify whether field is|isn't final
453 * @return string with class attributes and their types
455 def private generateFields(boolean _final) '''
456 «IF properties !== null»
458 private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
459 «val restrictions = f.returnType.restrictions»
460 «IF !_final && restrictions != null»
461 «IF !(restrictions.lengthConstraints.empty)»
462 private static «List.importedName»<«Range.importedName»<«f.returnType.importedNumber»>> «f.fieldName»_length;
464 «IF !(restrictions.rangeConstraints.empty)»
465 private static «List.importedName»<«Range.importedName»<«f.returnType.importedNumber»>> «f.fieldName»_range;
472 def private generateAugmentField(boolean isPrivate) '''
473 «IF augmentField != null»
474 «IF isPrivate»private «ENDIF»«Map.importedName»<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>();
479 * Template method which generates setter methods
481 * @return string with the setter methods
483 def private generateSetters() '''
484 «FOR field : properties SEPARATOR '\n'»
485 «val length = field.fieldName + "_length"»
486 «val range = field.fieldName + "_range"»
487 public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) {
488 «generateRestrictions(field, "value", length, range)»
489 this.«field.fieldName» = value;
492 «generateLengthMethod(length, field.returnType, type.name+BUILDER, length)»
493 «generateRangeMethod(range, field.returnType.restrictions, field.returnType, type.name+BUILDER, range)»
495 «IF augmentField != null»
497 public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(«Class.importedName»<? extends «augmentField.returnType.importedName»> augmentationType, «augmentField.returnType.importedName» augmentation) {
498 this.«augmentField.name».put(augmentationType, augmentation);
504 def generateRestrictions(GeneratedProperty field, String paramName, String lengthGetter, String rangeGetter) '''
505 «val Type type = field.returnType»
506 «IF type instanceof ConcreteType»
507 «createRestrictions(type, paramName, type.name.contains("["), lengthGetter, rangeGetter)»
508 «ELSEIF type instanceof GeneratedTransferObject»
509 «createRestrictions(type, paramName, isArrayType(type as GeneratedTransferObject), lengthGetter, rangeGetter)»
513 def private createRestrictions(Type type, String paramName, boolean isArray, String lengthGetter, String rangeGetter) '''
514 «val restrictions = type.getRestrictions»
515 «IF restrictions !== null»
516 «val boolean isNestedType = !(type instanceof ConcreteType)»
517 «IF !restrictions.lengthConstraints.empty»
518 «generateLengthRestriction(type, paramName, lengthGetter, isNestedType, isArray)»
520 «IF !restrictions.rangeConstraints.empty»
521 «generateRangeRestriction(type, paramName, rangeGetter, isNestedType)»
526 def private generateLengthRestriction(Type type, String paramName, String getterName, boolean isNestedType, boolean isArray) '''
527 «val restrictions = type.getRestrictions»
528 if («paramName» != null) {
529 «val clazz = restrictions.lengthConstraints.iterator.next.min.class»
530 «printLengthConstraint(type, clazz, paramName, isNestedType, isArray)»
531 boolean isValidLength = false;
532 for («Range.importedName»<«clazz.importedNumber»> r : «getterName»()) {
533 if (r.contains(_constraint)) {
534 isValidLength = true;
537 if (!isValidLength) {
538 throw new IllegalArgumentException(String.format("Invalid length: %s, expected: %s.", «paramName», «getterName»));
543 def private generateRangeRestriction(Type type, String paramName, String getterName, boolean isNestedType) '''
544 if («paramName» != null) {
545 «printRangeConstraint(type, paramName, isNestedType)»
546 boolean isValidRange = false;
547 for («Range.importedName»<«type.importedNumber»> r : «getterName»()) {
548 if (r.contains(_constraint)) {
553 throw new IllegalArgumentException(String.format("Invalid range: %s, expected: %s.", «paramName», «getterName»));
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»
594 «IF !impl»if (base instanceof «type.name»«IMPL») {«ENDIF»
595 «IF !impl»«type.name»«IMPL» _impl = («type.name»«IMPL») base;«ENDIF»
596 «val prop = if (impl) "base" else "_impl"»
598 switch («prop».«augmentField.name».size()) {
600 this.«augmentField.name» = «Collections.importedName».emptyMap();
603 final «Map.importedName».Entry<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e = «prop».«augmentField.name».entrySet().iterator().next();
604 this.«augmentField.name» = «Collections.importedName».<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
607 this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»);
610 this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»);
617 private def boolean implementsIfc(GeneratedType type, Type impl) {
618 for (Type ifc : type.implements) {
619 if (ifc.equals(impl)) {
626 private def Type getKey(GeneratedType type) {
627 for (m : type.methodDefinitions) {
628 if ("getKey".equals(m.name)) {
635 private def void removeProperty(Collection<GeneratedProperty> props, String name) {
636 var GeneratedProperty toRemove = null
638 if (p.name.equals(name)) {
642 if (toRemove != null) {
643 props.remove(toRemove);
648 * Template method which generate getter methods for IMPL class.
650 * @return string with getter methods
652 def private generateGetters(boolean addOverride) '''
653 «IF !properties.empty»
654 «FOR field : properties SEPARATOR '\n'»
655 «IF addOverride»@Override«ENDIF»
659 «IF augmentField != null»
661 @SuppressWarnings("unchecked")
662 «IF addOverride»@Override«ENDIF»
663 public <E extends «augmentField.returnType.importedName»> E get«augmentField.name.toFirstUpper»(«Class.importedName»<E> augmentationType) {
664 if (augmentationType == null) {
665 throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
667 return (E) «augmentField.name».get(augmentationType);
673 * Template method which generates the method <code>hashCode()</code>.
675 * @return string with the <code>hashCode()</code> method definition in JAVA format
677 def protected generateHashCode() '''
678 «IF !properties.empty || augmentField != null»
680 public int hashCode() {
681 final int prime = 31;
683 «FOR property : properties»
684 «IF property.returnType.name.contains("[")»
685 result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));
687 result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());
690 «IF augmentField != null»
691 result = prime * result + ((«augmentField.name» == null) ? 0 : «augmentField.name».hashCode());
699 * Template method which generates the method <code>equals()</code>.
701 * @return string with the <code>equals()</code> method definition in JAVA format
703 def protected generateEquals() '''
704 «IF !properties.empty || augmentField != null»
706 public boolean equals(«Object.importedName» obj) {
710 if (!(obj instanceof «DataObject.importedName»)) {
713 if (!«type.importedName».class.equals(((«DataObject.importedName»)obj).getImplementedInterface())) {
716 «type.importedName» other = («type.importedName»)obj;
717 «FOR property : properties»
718 «val fieldName = property.fieldName»
719 if («fieldName» == null) {
720 if (other.«property.getterMethodName»() != null) {
723 «IF property.returnType.name.contains("[")»
724 } else if(!«Arrays.importedName».equals(«fieldName», other.«property.getterMethodName»())) {
726 } else if(!«fieldName».equals(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 («fieldName» == null) {
737 if (otherImpl.«fieldName» != null) {
740 } else if(!«fieldName».equals(otherImpl.«fieldName»)) {
744 // Hard case: compare our augments with presence there...
745 for («Map.importedName».Entry<«Class.importedName»<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e : «augmentField.name».entrySet()) {
746 if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
750 // .. and give the other one the chance to do the same
751 if (!obj.equals(this)) {
761 def override generateToString(Collection<GeneratedProperty> properties) '''
762 «IF !(properties === null)»
764 public «String.importedName» toString() {
765 «StringBuilder.importedName» builder = new «StringBuilder.importedName» ("«type.name» [");
766 boolean first = true;
768 «FOR property : properties»
769 if («property.fieldName» != null) {
773 builder.append(", ");
775 builder.append("«property.fieldName»=");
776 «IF property.returnType.name.contains("[")»
777 builder.append(«Arrays.importedName».toString(«property.fieldName»));
779 builder.append(«property.fieldName»);
783 «IF augmentField != null»
787 builder.append(", ");
789 builder.append("«augmentField.name»=");
790 builder.append(«augmentField.name».values());
792 return builder.append(']').toString();
797 override protected getFullyQualifiedName() {
798 '''«type.fullyQualifiedName»Builder'''.toString
801 def implementedInterfaceGetter() '''
802 public «Class.importedName»<«type.importedName»> getImplementedInterface() {
803 return «type.importedName».class;
807 private def createDescription(GeneratedType type) {
809 Class that builds {@link «type.importedName»} instances.
811 @see «type.importedName»
815 override def protected String formatDataForJavaDoc(GeneratedType type) {
816 val typeDescription = createDescription(type)
819 «IF !typeDescription.nullOrEmpty»