001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.rdf.owl2java; 031 032import java.io.File; 033import java.io.FileNotFoundException; 034import java.io.PrintStream; 035import java.io.UnsupportedEncodingException; 036import java.util.Arrays; 037import java.util.HashMap; 038import java.util.HashSet; 039import java.util.Iterator; 040import java.util.Map; 041import java.util.Set; 042 043import org.apache.commons.lang.WordUtils; 044import org.joda.time.DateTime; 045import org.openimaj.rdf.owl2java.Generator.GeneratorOptions; 046import org.openrdf.model.URI; 047import org.openrdf.model.Value; 048import org.openrdf.query.BindingSet; 049import org.openrdf.query.MalformedQueryException; 050import org.openrdf.query.QueryEvaluationException; 051import org.openrdf.query.QueryLanguage; 052import org.openrdf.query.TupleQuery; 053import org.openrdf.query.TupleQueryResult; 054import org.openrdf.repository.RepositoryConnection; 055import org.openrdf.repository.RepositoryException; 056import org.openrdf.sail.memory.model.MemBNode; 057import org.openrdf.sail.memory.model.MemLiteral; 058import org.openrdf.sail.memory.model.MemStatement; 059import org.openrdf.sail.memory.model.MemStatementList; 060 061/** 062 * Represents the definition of an ontology class. 063 * 064 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 065 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 066 * @created 29 Oct 2012 067 * @version $Author$, $Revision$, $Date$ 068 */ 069public class ClassDef 070{ 071 /** The description of the class from the RDF comment */ 072 protected String comment; 073 074 /** The URI of the class */ 075 protected URI uri; 076 077 /** 078 * List of the all the ancestral superclasses to each of the direct 079 * superclasses 080 */ 081 protected Map<URI, Set<URI>> allSuperclasses; 082 083 /** A list of the direct superclasses of this class */ 084 protected Set<URI> directSuperclasses; 085 086 /** List of the properties in this class */ 087 protected Set<PropertyDef> properties; 088 089 /** 090 * Outputs the Java class definition for this class def 091 * 092 * {@inheritDoc} 093 * 094 * @see java.lang.Object#toString() 095 */ 096 @Override 097 public String toString() 098 { 099 return "class " + this.uri.getLocalName() + " extends " + 100 this.allSuperclasses + " {\n" + "\t" + this.properties + "\n}\n"; 101 } 102 103 /** 104 * Loads all the class definitions from the given repository 105 * 106 * @param conn 107 * The repository connection from where to get the classes 108 * @param go 109 * @return a Map that maps class URIs to ClassDef objects 110 * @throws RepositoryException 111 * @throws MalformedQueryException 112 * @throws QueryEvaluationException 113 */ 114 public static Map<URI, ClassDef> loadClasses(final GeneratorOptions go, final RepositoryConnection conn) 115 throws RepositoryException, MalformedQueryException, QueryEvaluationException 116 { 117 final HashMap<URI, ClassDef> classes = new HashMap<URI, ClassDef>(); 118 119 // This is the types we'll look for 120 // We'll look for both OWL and RDF classes 121 final String[] clzTypes = { 122 "<http://www.w3.org/2002/07/owl#Class>", 123 "rdfs:Class" 124 }; 125 126 // Loop over the namespaces 127 for (final String clzType : clzTypes) 128 { 129 // Create a query to get the classes 130 final String query = "SELECT Class, Comment " 131 + "FROM {Class} rdf:type {" + clzType + "}; " 132 + " [ rdfs:comment {Comment} ]"; 133 134 // Prepare the query... 135 final TupleQuery preparedQuery = conn.prepareTupleQuery( 136 QueryLanguage.SERQL, query); 137 138 // Run the query... 139 final TupleQueryResult res = preparedQuery.evaluate(); 140 141 // Loop over the results 142 while (res.hasNext()) 143 { 144 final BindingSet bindingSet = res.next(); 145 146 // If we have a class with a URI... 147 if (bindingSet.getValue("Class") instanceof URI) 148 { 149 // Create a new class definition for it 150 final ClassDef clz = new ClassDef(); 151 152 // Get the comment, if there is one. 153 if (bindingSet.getValue("Comment") != null) 154 { 155 final MemLiteral lit = (MemLiteral) 156 bindingSet.getValue("Comment"); 157 clz.comment = lit.stringValue(); 158 } 159 160 clz.uri = (URI) bindingSet.getValue("Class"); 161 clz.directSuperclasses = ClassDef.getSuperclasses(clz.uri, conn); 162 clz.properties = PropertyDef.loadProperties(go, clz.uri, conn); 163 164 // Check whether there are any other classes 165 ClassDef.getEquivalentClasses(clz, conn); 166 167 // Get all the superclasses in the tree 168 clz.allSuperclasses = clz.getAllSuperclasses(conn); 169 170 classes.put(clz.uri, clz); 171 } 172 } 173 } 174 return classes; 175 } 176 177 /** 178 * Checks for owl:equivalentClass and updates the class definition based on 179 * whats found. 180 * 181 * @param clz 182 * the class definition 183 * @param conn 184 * The connection to the repository 185 */ 186 private static void getEquivalentClasses(final ClassDef clz, final RepositoryConnection conn) 187 { 188 try 189 { 190 final String sparql = "prefix owl: <http://www.w3.org/2002/07/owl#> " + 191 "SELECT ?clazz WHERE " + 192 "{ <" + clz.uri + "> owl:equivalentClass ?clazz . }"; 193 194 // System.out.println( sparql ); 195 196 // Prepare the query... 197 final TupleQuery preparedQuery = conn.prepareTupleQuery( 198 QueryLanguage.SPARQL, sparql); 199 200 // Run the query... 201 final TupleQueryResult res = preparedQuery.evaluate(); 202 203 // Loop through the results (if any) 204 while (res.hasNext()) 205 { 206 final BindingSet bs = res.next(); 207 208 final Value clazz = bs.getBinding("clazz").getValue(); 209 210 // If it's an equivalent then we'll simply make this class 211 // a subclass of the equivalent class. 212 // TODO: There is a possibility that we could end up with a 213 // cycle here 214 // and the resulting code would not compile. 215 if (clazz instanceof URI) 216 clz.directSuperclasses.add((URI) clazz); 217 else 218 // If it's a BNode, then the BNode defines the equivalence. 219 if (clazz instanceof MemBNode) 220 { 221 final MemBNode b = (MemBNode) clazz; 222 final MemStatementList sl = b.getSubjectStatementList(); 223 224 for (int i = 0; i < sl.size(); i++) 225 { 226 final MemStatement x = sl.get(i); 227 System.out.println(" -> " + x); 228 } 229 } 230 } 231 232 res.close(); 233 } catch (final RepositoryException e) 234 { 235 e.printStackTrace(); 236 } catch (final MalformedQueryException e) 237 { 238 e.printStackTrace(); 239 } catch (final QueryEvaluationException e) 240 { 241 e.printStackTrace(); 242 } 243 } 244 245 /** 246 * Retrieves the superclass list for the given class URI using the given 247 * repository 248 * 249 * @param uri 250 * The URI of the class to find the allSuperclasses of 251 * @param conn 252 * The respository 253 * @return A list of URIs of allSuperclasses 254 * 255 * @throws RepositoryException 256 * @throws MalformedQueryException 257 * @throws QueryEvaluationException 258 */ 259 private static Set<URI> getSuperclasses(final URI uri, final RepositoryConnection conn) 260 throws RepositoryException, MalformedQueryException, QueryEvaluationException 261 { 262 // SPARQL query to get the allSuperclasses 263 final String query = "SELECT ?superclass WHERE { " + 264 "<" + uri.stringValue() + "> " + 265 "<http://www.w3.org/2000/01/rdf-schema#subClassOf> " + 266 "?superclass. }"; 267 268 final TupleQuery preparedQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, query); 269 final TupleQueryResult res = preparedQuery.evaluate(); 270 271 final Set<URI> superclasses = new HashSet<URI>(); 272 while (res.hasNext()) { 273 final BindingSet bindingSet = res.next(); 274 275 if (bindingSet.getValue("superclass") instanceof URI) { 276 superclasses.add((URI) bindingSet.getValue("superclass")); 277 } 278 } 279 280 return superclasses; 281 } 282 283 /** 284 * Generates a Java file in the target directory 285 * 286 * @param targetDir 287 * The target directory 288 * @param pkgs 289 * A map of package mappings to class URIs 290 * @param classes 291 * A map of class URIs to ClassDefs 292 * @param flattenClassStructure 293 * Whether to flatten the class structure 294 * @param generateAnnotations 295 * Whether to generate OpenIMAJ RDF annotations for the 296 * properties 297 * @param separateImplementations 298 * @throws FileNotFoundException 299 */ 300 public void generateClass(final File targetDir, final Map<URI, String> pkgs, 301 final Map<URI, ClassDef> classes, final boolean flattenClassStructure, 302 final boolean generateAnnotations, final boolean separateImplementations) throws FileNotFoundException 303 { 304 // We don't need to generate an implementation file if there are no 305 // properties to get/set 306 // if (this.properties.size() == 0) 307 // return; 308 309 // Generate the filename for the output file 310 final File path = new File(targetDir.getAbsolutePath() + File.separator + 311 pkgs.get(this.uri).replace(".", File.separator) + 312 (separateImplementations ? File.separator + "impl" : "")); 313 path.mkdirs(); 314 PrintStream ps; 315 try 316 { 317 ps = new PrintStream(new File(path.getAbsolutePath() 318 + File.separator + Generator.getTypeName(this.uri) + "Impl.java"), 319 "UTF-8"); 320 } catch (final UnsupportedEncodingException e) 321 { 322 e.printStackTrace(); 323 return; 324 } 325 326 // Output the package definition 327 ps.println("package " + pkgs.get(this.uri) + 328 (separateImplementations ? ".impl" : "") + ";"); 329 ps.println(); 330 331 // Output the imports 332 ps.println("import org.openimaj.rdf.owl2java.Something;"); 333 if (separateImplementations) 334 ps.println("import " + pkgs.get(this.uri) + ".*;"); 335 if (generateAnnotations) 336 { 337 ps.println("import org.openimaj.rdf.serialize.Predicate;\n"); 338 ps.println("import org.openimaj.rdf.serialize.RDFType;\n"); 339 } 340 this.printImports(ps, pkgs, false, classes, true); 341 ps.println(); 342 343 // Output the comment at the top of the class 344 this.printClassComment(ps); 345 346 // Output the class 347 ps.print("@RDFType(\"" + this.uri + "\")\n"); 348 ps.print("public class " + Generator.getTypeName(this.uri) + "Impl "); 349 ps.print("extends Something "); 350 351 // It will implement the interface that defines it 352 ps.print("implements " + Generator.getTypeName(this.uri)); 353 354 // if (this.superclasses.size() > 0) 355 // { 356 // // ...and any of the super class interfaces 357 // for( final URI superclass : this.superclasses ) 358 // { 359 // ps.print(", "); 360 // ps.print( Generator.getTypeName( superclass ) ); 361 // } 362 // } 363 ps.println("\n{"); 364 365 // Output the definition of the class 366 this.printClassPropertyDefinitions(ps, classes, 367 flattenClassStructure, generateAnnotations); 368 369 ps.println("}\n"); 370 } 371 372 /** 373 * Generates a Java interface file in the target directory 374 * 375 * @param targetDir 376 * The target directory 377 * @param pkgs 378 * A list of package mappings to class URIs 379 * @param classes 380 * The URI to class definition map. 381 * @throws FileNotFoundException 382 */ 383 public void generateInterface(final File targetDir, final Map<URI, String> pkgs, 384 final Map<URI, ClassDef> classes) throws FileNotFoundException 385 { 386 final File path = new File(targetDir.getAbsolutePath() + File.separator + 387 pkgs.get(this.uri).replace(".", File.separator)); 388 path.mkdirs(); 389 PrintStream ps; 390 try 391 { 392 ps = new PrintStream(new File(path.getAbsolutePath() 393 + File.separator + Generator.getTypeName(this.uri) + ".java"), 394 "UTF-8"); 395 } catch (final UnsupportedEncodingException e) 396 { 397 e.printStackTrace(); 398 return; 399 } 400 401 ps.println("package " + pkgs.get(this.uri) + ";"); 402 ps.println(); 403 this.printImports(ps, pkgs, true, classes, false); 404 ps.println(); 405 406 this.printClassComment(ps); 407 408 ps.print("public interface " + Generator.getTypeName(this.uri) + " "); 409 if (this.allSuperclasses.size() > 0) 410 { 411 ps.print("\n\textends "); 412 boolean first = true; 413 for (final URI superClassURI : this.directSuperclasses) 414 { 415 if (!first) 416 ps.print(", "); 417 ps.print(Generator.getTypeName(superClassURI)); 418 first = false; 419 } 420 } 421 422 ps.println("\n{"); 423 this.printInterfacePropertyDefinitions(ps); 424 ps.println("\tpublic String getURI();\n"); 425 ps.println("}\n"); 426 } 427 428 /** 429 * Prints the comment at the top of the file for this class. 430 * 431 * @param ps 432 * The stream to print the comment to. 433 */ 434 private void printClassComment(final PrintStream ps) 435 { 436 ps.println("/**"); 437 if (this.comment == null) { 438 ps.println(" * " + this.uri); 439 } else { 440 final String cmt = WordUtils.wrap(" * " + 441 this.comment.replaceAll("\\r?\\n", " "), 80, "\n * ", false); 442 ps.println(" " + cmt); 443 } 444 445 ps.println(" *"); 446 ps.println(" *\t@created " + new DateTime()); 447 ps.println(" *\t@generated by owl2java from OpenIMAJ"); 448 ps.println(" */"); 449 } 450 451 /** 452 * Outputs the list of imports necessary for this class. 453 * 454 * @param ps 455 * The stream to print the imports to 456 * @param pkgs 457 * The list of package mappings for all the known classes 458 * @param allSuperclasses 459 * Whether to print imports for allSuperclasses 460 */ 461 private void printImports(final PrintStream ps, final Map<URI, String> pkgs, 462 final boolean superclasses, final Map<URI, ClassDef> classes, 463 final boolean implementations) 464 { 465 final Set<String> imports = new HashSet<String>(); 466 467 final Map<PropertyDef, String> pd = new HashMap<PropertyDef, String>(); 468 final Map<String, String> instanceNameMap = new HashMap<String, String>(); 469 this.getFullPropertyList(pd, instanceNameMap, classes); 470 471 for (final PropertyDef p : pd.keySet()) 472 if (implementations || pd.get(p).equals("this")) 473 if (p.needsImport(implementations) != null) 474 imports.addAll(p.needsImport(implementations)); 475 476 if (superclasses) 477 { 478 for (final URI u : this.directSuperclasses) { 479 imports.add(pkgs.get(u) + "."); 480 // TODO - impl package should depend on configuration 481 imports.add(pkgs.get(u) + ".impl."); 482 } 483 } 484 485 imports.remove(pkgs.get(this.uri) + "."); 486 487 final String[] sortedImports = imports.toArray(new String[imports.size()]); 488 Arrays.sort(sortedImports); 489 490 for (final String imp : sortedImports) { 491 if (imp.endsWith(".")) 492 ps.println("import " + imp + "*;"); 493 else 494 ps.println("import " + imp + ";"); 495 } 496 } 497 498 /** 499 * Outputs all the properties into the class definition. 500 * 501 * @param ps 502 * The stream to print to. 503 */ 504 private void printInterfacePropertyDefinitions(final PrintStream ps) 505 { 506 for (final PropertyDef p : this.properties) 507 ps.println(p.toSettersAndGetters("\t", false, null, false)); 508 } 509 510 /** 511 * Outputs all the properties into the class definition. 512 * 513 * @param ps 514 * The stream to print to. 515 * @param classes 516 * A map of class URIs to ClassDefs 517 * @param flattenClassStructure 518 * Whether to combine all the properties from all the 519 * allSuperclasses into this class (TRUE), or whether to use 520 * instance pointers to classes of that type (FALSE) 521 * @param generateAnnotations 522 */ 523 private void printClassPropertyDefinitions(final PrintStream ps, 524 final Map<URI, ClassDef> classes, final boolean flattenClassStructure, 525 final boolean generateAnnotations) 526 { 527 // Remember which ones we've output already 528 final HashSet<URI> alreadyDone = new HashSet<URI>(); 529 530 if (flattenClassStructure) 531 { 532 // TODO: Check this still works after the change in properties list 533 // Work out all the properties to output 534 final Set<PropertyDef> pd = new HashSet<PropertyDef>(); 535 pd.addAll(this.properties); 536 for (final Set<URI> superclassList : this.allSuperclasses.values()) 537 { 538 for (final URI superclass : superclassList) 539 { 540 if (!alreadyDone.contains(superclass)) 541 { 542 pd.addAll(classes.get(superclass).properties); 543 alreadyDone.add(superclass); 544 } 545 } 546 } 547 548 // Output all the property definitions for this class. 549 for (final PropertyDef p : pd) 550 ps.println(p.toJavaDefinition("\t", generateAnnotations)); 551 ps.println(); 552 // Output all the getters and setters for this class. 553 for (final PropertyDef p : pd) 554 ps.println(p.toSettersAndGetters("\t", true, null, false)); 555 } 556 else 557 { 558 System.out.println("======================================="); 559 System.out.println(this.uri); 560 System.out.println("======================================="); 561 System.out.println("Direct superclasses: " + this.directSuperclasses); 562 563 // Output all the property definitions for this class. 564 for (final PropertyDef p : this.properties) 565 ps.println(p.toJavaDefinition("\t", generateAnnotations)); 566 ps.println(); 567 568 // Now we need to output the links to other objects from which 569 // this class inherits. While we do that, we'll also remember which 570 // properties we need to delegate to the other objects. 571 final HashMap<PropertyDef, String> pd = new HashMap<PropertyDef, String>(); 572 final HashMap<String, String> entityNameMap = new HashMap<String, String>(); 573 this.getFullPropertyList(pd, entityNameMap, classes); 574 575 // Check whether there are any delegation members to output 576 // We do this by removing "this" from the map and seeing what's 577 // left. 578 final Map<PropertyDef, String> xx = new HashMap<PropertyDef, String>(); 579 xx.putAll(pd); 580 final HashSet<String> delegatesToOutput = new HashSet<String>(); 581 final Iterator<String> i = xx.values().iterator(); 582 String xxx = null; 583 while (i.hasNext()) 584 if (!(xxx = i.next()).equals("this")) 585 { 586 delegatesToOutput.add(xxx); 587 } 588 System.out.println(xx); 589 System.out.println(entityNameMap); 590 System.out.println(delegatesToOutput); 591 if (delegatesToOutput.size() > 0) 592 { 593 for (final String instanceName : delegatesToOutput) 594 { 595 final String typeName = entityNameMap.get(instanceName); 596 ps.println("\t/** " + typeName + " superclass instance */"); 597 ps.println("\tprivate " + typeName + " " + instanceName + " = new " + typeName + "Impl();\n"); 598 } 599 } 600 601 // Now output the delegated getters and setters for this class 602 for (final PropertyDef pp : pd.keySet()) 603 { 604 final String instanceName = pd.get(pp); 605 ps.println("\n\t// From class " + instanceName + "\n\n"); 606 ps.println(pp.toSettersAndGetters("\t", true, instanceName, false)); 607 } 608 } 609 } 610 611 /** 612 * Traverses up the tree from this class to find all ancestor 613 * allSuperclasses. 614 * 615 * @param conn 616 * A connection to a triple-store repository 617 * @return A list of URIs representing the superclass ancestors of this 618 * class 619 */ 620 public Map<URI, Set<URI>> getAllSuperclasses(final RepositoryConnection conn) 621 { 622 final HashMap<URI, Set<URI>> map = new HashMap<URI, Set<URI>>(); 623 for (final URI uri : this.directSuperclasses) 624 { 625 final HashSet<URI> uris = new HashSet<URI>(); 626 ClassDef.getAllSuperclasses(uri, conn, uris); 627 map.put(uri, uris); 628 } 629 630 return map; 631 } 632 633 /** 634 * For the given URI, will query the repository and fill the list of URIs 635 * with the URIs of all the ancestor allSuperclasses to the given URI. 636 * 637 * @param uri 638 * The URI of the class to find the ancestors of 639 * @param conn 640 * A connection to a triple-store repository. 641 * @param uris 642 * The list where classes are to be added 643 */ 644 private static void getAllSuperclasses(final URI uri, 645 final RepositoryConnection conn, final Set<URI> uris) 646 { 647 try 648 { 649 final Set<URI> superclassesOf = ClassDef.getSuperclasses(uri, conn); 650 uris.addAll(superclassesOf); 651 for (final URI u : superclassesOf) 652 ClassDef.getAllSuperclasses(u, conn, uris); 653 } catch (final RepositoryException e) 654 { 655 e.printStackTrace(); 656 } catch (final MalformedQueryException e) 657 { 658 e.printStackTrace(); 659 } catch (final QueryEvaluationException e) 660 { 661 e.printStackTrace(); 662 } 663 } 664 665 /** 666 * Returns a full list of all the properties for all the classes in the 667 * tree. 668 * 669 * @param pd 670 * The set of property definitions (linked to instance name) to 671 * fill 672 * @param instanceNameMap 673 * The list of property to instance name map 674 * @param classes 675 * The definition of all the classes in the ontology 676 */ 677 private void getFullPropertyList(final Map<PropertyDef, String> pd, 678 final Map<String, String> instanceNameMap, final Map<URI, ClassDef> classes) 679 { 680 for (final PropertyDef pp : this.properties) 681 pd.put(pp, "this"); 682 683 for (final URI superclass : this.directSuperclasses) 684 { 685 final String instanceName = 686 superclass.getLocalName().substring(0, 1).toLowerCase() + 687 superclass.getLocalName().substring(1); 688 689 for (final PropertyDef pp : classes.get(superclass).properties) 690 pd.put(pp, instanceName); 691 692 // map all the properties of the ancestors of this direct subclass 693 // to the instance name of the direct superclass. This will make all 694 // the getters and setters use the superclass instance to access the 695 // ancestor properties. 696 for (final URI ancestorURI : this.allSuperclasses.get(superclass)) 697 { 698 for (final PropertyDef pp : classes.get(ancestorURI).properties) 699 pd.put(pp, instanceName); 700 } 701 702 // We don't need the instance variable if we're not inheriting 703 // any properties from the superclasses. 704 if (pd.keySet().size() == 0) 705 continue; 706 707 // Check we've not already got a delegation for that instance 708 if (instanceNameMap.get(instanceName) == null) 709 { 710 instanceNameMap.put(instanceName, 711 /* Generator.getPackageName(superclass) + "." + */ 712 Generator.getTypeName(superclass)); 713 } 714 } 715 } 716}