| /* |
| * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.internal.codegen; |
| |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| import java.util.Vector; |
| |
| import org.eclipse.persistence.internal.helper.Helper; |
| |
| /** |
| * INTERNAL: |
| * <p><b>Purpose</b>: Model a class for code generation purposes. |
| * |
| * @since TopLink 3.0 |
| * @author James Sutherland |
| */ |
| public class ClassDefinition extends CodeDefinition { |
| protected String packageName; |
| protected Vector imports; |
| protected int type; |
| public static final int CLASS_TYPE = 1; |
| public static final int INTERFACE_TYPE = 2; |
| protected String superClass; |
| protected Vector interfaces; |
| protected Vector attributes; |
| protected Vector methods; |
| protected Vector innerClasses; |
| |
| public ClassDefinition() { |
| this.packageName = ""; |
| this.imports = new Vector(3); |
| this.type = CLASS_TYPE; |
| this.interfaces = new Vector(3); |
| this.attributes = new Vector(); |
| this.methods = new Vector(); |
| this.innerClasses = new Vector(3); |
| } |
| |
| public void addAttribute(AttributeDefinition attribute) { |
| getAttributes().addElement(attribute); |
| } |
| |
| /** |
| * The importStatement should be of the form |
| * "{packageName}.{shortName or '*'}" |
| */ |
| public void addImport(String importStatement) { |
| if (!getImports().contains(importStatement)) { |
| getImports().addElement(importStatement); |
| } |
| } |
| |
| private void addImports(Map typeNameMap) { |
| for (Map.Entry<String, Set<String>> entry : (Set<Map.Entry<String, Set<String>>>) typeNameMap.entrySet()) { |
| String shortName = entry.getKey(); |
| Set<String> packageNames = entry.getValue(); |
| |
| if (packageNames.size() > 1) { |
| continue; |
| } |
| |
| for (String packageName : packageNames) { |
| if (!packageName.equals(JAVA_LANG_PACKAGE_NAME) && !packageName.equals(getPackageName()) && !packageName.equals("")) { |
| addImport(packageName + "." + shortName); |
| } |
| } |
| } |
| |
| sortImports(); |
| } |
| |
| public void addInnerClass(ClassDefinition classDefinition) { |
| getInnerClasses().add(classDefinition); |
| } |
| |
| public void addInterface(String interfaceClassName) { |
| getInterfaces().addElement(interfaceClassName); |
| } |
| |
| public void addMethod(MethodDefinition method) { |
| getMethods().addElement(method); |
| } |
| |
| private void addTypeNamesToMap(HashMap typeNameMap) { |
| putTypeNameInMap(getSuperClass(), typeNameMap); |
| |
| for (Iterator i = getInterfaces().iterator(); i.hasNext();) { |
| putTypeNameInMap((String)i.next(), typeNameMap); |
| } |
| |
| for (Iterator i = getAttributes().iterator(); i.hasNext();) { |
| ((AttributeDefinition)i.next()).putTypeNamesInMap(typeNameMap); |
| } |
| |
| for (Iterator i = getMethods().iterator(); i.hasNext();) { |
| ((MethodDefinition)i.next()).putTypeNamesInMap(typeNameMap); |
| } |
| } |
| |
| private void adjustTypeNames(HashMap typeNameMap) { |
| setSuperClass(adjustTypeName(getSuperClass(), typeNameMap)); |
| |
| for (Iterator i = new Vector(getInterfaces()).iterator(); i.hasNext();) { |
| String interfaceName = (String)i.next(); |
| replaceInterface(interfaceName, adjustTypeName(interfaceName, typeNameMap)); |
| } |
| |
| for (Iterator i = getAttributes().iterator(); i.hasNext();) { |
| ((AttributeDefinition)i.next()).adjustTypeNames(typeNameMap); |
| } |
| |
| for (Iterator i = getMethods().iterator(); i.hasNext();) { |
| ((MethodDefinition)i.next()).adjustTypeNames(typeNameMap); |
| } |
| } |
| |
| /** |
| * Parses the class definition, pulls out fully qualified class names, |
| * adds imports for them, and un-fully qualifies the class names. |
| * - Assumes that no imports have been previously added. |
| * - Assumes that all types have been fully qualified to start. |
| * - Will not unqualify ambiguous classes (java.util.Date and java.sql.Date). |
| * - Will not add imports for java.lang.* |
| * - Will not add imports for classes in the same package. |
| * - Will not parse method bodies, but will unqualify types it finds. |
| * |
| * ?? - Should unqualification occur during writing? That way, reflective definitions could take advantage. |
| * |
| */ |
| public void calculateImports() { |
| // Calculate type name map for class definition. |
| // Key - short type name, Value - Set of package names for that type name |
| HashMap typeNameMap = new HashMap(); |
| addTypeNamesToMap(typeNameMap); |
| |
| // Go back through class def, pulling out imports and removing package names from |
| // non-repeated short type names. |
| adjustTypeNames(typeNameMap); |
| |
| // Finally, add the imports |
| addImports(typeNameMap); |
| } |
| |
| public boolean containsMethod(MethodDefinition method) { |
| return getMethods().contains(method); |
| } |
| |
| protected Vector getAttributes() { |
| return attributes; |
| } |
| |
| protected Vector getImports() { |
| return imports; |
| } |
| |
| protected Vector getInnerClasses() { |
| return innerClasses; |
| } |
| |
| protected Vector getInterfaces() { |
| return interfaces; |
| } |
| |
| protected Vector getMethods() { |
| return methods; |
| } |
| |
| public String getPackageName() { |
| return packageName; |
| } |
| |
| public String getSuperClass() { |
| return superClass; |
| } |
| |
| public int getType() { |
| return type; |
| } |
| |
| public boolean isInterface() { |
| return getType() == INTERFACE_TYPE; |
| } |
| |
| protected void replaceInterface(String oldInterfaceName, String newInterfaceName) { |
| // Don't bother sorting |
| if (!oldInterfaceName.equals(newInterfaceName)) { |
| this.interfaces.remove(oldInterfaceName); |
| this.interfaces.add(newInterfaceName); |
| } |
| } |
| |
| private void setImports(Vector imports) { |
| this.imports = imports; |
| } |
| |
| private void setMethods(Vector methods) { |
| this.methods = methods; |
| } |
| |
| public void setPackageName(String packageName) { |
| this.packageName = packageName; |
| } |
| |
| /** |
| * If the class to be generated is an interface, do not use this method. |
| * Instead, use addInterface(String) for each interface superclass. |
| */ |
| public void setSuperClass(String superClass) { |
| this.superClass = superClass; |
| } |
| |
| public void setType(int type) { |
| this.type = type; |
| } |
| |
| protected void sortImports() { |
| setImports(new Vector(new TreeSet(getImports()))); |
| } |
| |
| protected void sortMethods() { |
| //Object methodArray[] = getMethods().toArray(); |
| Object[] methodArray = Helper.arrayFromVector(getMethods()); |
| |
| Comparator comparison = new Comparator() { |
| @Override |
| public int compare(Object first, Object second) { |
| if (((MethodDefinition)first).isConstructor()) { |
| return -1; |
| } else if (((MethodDefinition)second).isConstructor()) { |
| return 1; |
| } else { |
| return ((MethodDefinition)first).getName().compareTo(((MethodDefinition)second).getName()); |
| } |
| } |
| }; |
| |
| Arrays.sort(methodArray, comparison); |
| |
| Vector sortedMethods = new Vector(getMethods().size()); |
| for (int index = 0; index < methodArray.length; index++) { |
| sortedMethods.addElement(methodArray[index]); |
| } |
| |
| setMethods(sortedMethods); |
| } |
| |
| /** |
| * Write the code out to the generator's stream. |
| */ |
| @Override |
| public void write(CodeGenerator generator) { |
| if (getPackageName().length() > 0) { |
| generator.write("package "); |
| generator.write(getPackageName()); |
| generator.writeln(";"); |
| generator.cr(); |
| } |
| |
| for (Enumeration importsEnum = getImports().elements(); importsEnum.hasMoreElements();) { |
| String importLine = (String)importsEnum.nextElement(); |
| generator.write("import "); |
| generator.write(importLine); |
| generator.writeln(";"); |
| } |
| if (!getImports().isEmpty()) { |
| generator.cr(); |
| } |
| super.write(generator); |
| } |
| |
| /** |
| * Write the code out to the generator's stream. |
| */ |
| @Override |
| public void writeBody(CodeGenerator generator) { |
| sortMethods(); |
| |
| if (isInterface()) { |
| generator.write("interface "); |
| } else { |
| generator.write("class "); |
| } |
| |
| generator.write(getName()); |
| |
| if (!isInterface() && (getSuperClass() != null)) { |
| generator.write(" extends "); |
| generator.writeType(getSuperClass()); |
| } |
| |
| boolean isFirst = true; |
| for (Enumeration interfacesEnum = getInterfaces().elements(); |
| interfacesEnum.hasMoreElements();) { |
| String interfaceName = (String)interfacesEnum.nextElement(); |
| |
| if (isFirst) { |
| if (isInterface()) { |
| generator.write(" extends"); |
| } else { |
| generator.write(" implements"); |
| } |
| |
| isFirst = false; |
| } else { |
| generator.write(","); |
| } |
| |
| generator.write(" "); |
| generator.write(interfaceName); |
| } |
| |
| generator.writeln(" {"); |
| generator.cr(); |
| |
| for (Enumeration attributesEnum = getAttributes().elements(); |
| attributesEnum.hasMoreElements();) { |
| generator.tab(); |
| ((AttributeDefinition)attributesEnum.nextElement()).write(generator); |
| generator.cr(); |
| } |
| |
| if (!getAttributes().isEmpty()) { |
| generator.cr(); |
| } |
| |
| for (Enumeration methodsEnum = getMethods().elements(); methodsEnum.hasMoreElements();) { |
| ((MethodDefinition)methodsEnum.nextElement()).write(generator); |
| generator.cr(); |
| generator.cr(); |
| } |
| |
| //used for Oc4j code gen |
| for (Enumeration innerClassesEnum = getInnerClasses().elements(); |
| innerClassesEnum.hasMoreElements();) { |
| ((ClassDefinition)innerClassesEnum.nextElement()).write(generator); |
| generator.cr(); |
| generator.cr(); |
| } |
| |
| generator.writeln("}"); |
| } |
| } |