| /* |
| * Copyright (c) 1998, 2021 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.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * INTERNAL: |
| * <p><b>Purpose</b>: Model a element of code generation purposes. |
| * |
| * @since TopLink 3.0 |
| * @author James Sutherland |
| */ |
| public abstract class CodeDefinition { |
| protected AccessLevel accessLevel; |
| protected String name; |
| protected String comment; |
| protected static final String JAVA_LANG_PACKAGE_NAME = "java.lang"; |
| protected static final String JAVA_UTIL_PACKAGE_NAME = "java.util"; |
| protected static final String TOPLINK_INDIRECTION_PACKAGE_NAME = "org.eclipse.persistence.indirection"; |
| |
| protected CodeDefinition() { |
| this.accessLevel = new AccessLevel(); |
| this.name = ""; |
| this.comment = ""; |
| } |
| |
| private static boolean adjustmentNeededForType(String typeName, Map typeNameMap) { |
| if ((typeName == null) || typeName.equals("")) { |
| return false; |
| } |
| |
| if (packageName(typeName).length() == 0) { |
| return false; |
| } |
| |
| Set packages = (Set)typeNameMap.get(shortName(typeName)); |
| return (packages == null) || (packages.size() <= 1); |
| } |
| |
| /** |
| * Compares the typeName to those stored in the typeNameMap. |
| * If the short name of the typeName is unambiguous (only one package for |
| * that short name in the Map), removes the package name and returns the |
| * short name, else returns the whole thing. |
| * |
| * Assumes that typeName contains only a package name (optional) and a short name, |
| * potentially with subtended brackets. |
| * |
| * (e.g. int -> int, java.util.Vector -> Vector, java.lang.Boolean[] -> Boolean[], etc.) |
| */ |
| protected static String adjustTypeName(String typeName, Map typeNameMap) { |
| if (adjustmentNeededForType(typeName, typeNameMap)) { |
| putTypeNameInMap(typeName, typeNameMap); |
| return typeName.substring(packageName(typeName).length() + 1); |
| } else { |
| return typeName; |
| } |
| } |
| |
| /** |
| * Returns a set of java.lang.String type names included in longString. |
| * Will only look for ValueHolder, java.util collection types, and TopLink |
| * indirect collection types. |
| * All other searches too intractable at this point. |
| */ |
| protected static Set parseForTypeNames(String longString) { |
| Set typeNames = new HashSet(); |
| |
| if (longString != null) { |
| typeNames.addAll(parseForTypeNamesInPackage(longString, JAVA_LANG_PACKAGE_NAME)); |
| typeNames.addAll(parseForTypeNamesInPackage(longString, JAVA_UTIL_PACKAGE_NAME)); |
| typeNames.addAll(parseForTypeNamesInPackage(longString, TOPLINK_INDIRECTION_PACKAGE_NAME)); |
| } |
| |
| return typeNames; |
| } |
| |
| private static Set parseForTypeNamesInPackage(String longString, String packageName) { |
| Set typeNames = new HashSet(); |
| int packageStartIndex = longString.indexOf(packageName); |
| |
| while (packageStartIndex != -1) { |
| boolean lookingForEndOfTypeName = true; |
| int searchIndex = packageStartIndex + packageName.length() + 1; |
| |
| while (lookingForEndOfTypeName) { |
| if (Character.isJavaIdentifierPart(longString.charAt(searchIndex))) { |
| searchIndex++; |
| } else { |
| lookingForEndOfTypeName = false; |
| } |
| } |
| |
| typeNames.add(longString.substring(packageStartIndex, searchIndex)); |
| packageStartIndex = longString.indexOf(packageName, searchIndex); |
| } |
| |
| return typeNames; |
| } |
| |
| /** |
| * Used for calculating imports. @see org.eclipse.persistence.internal.codegen.ClassDefinition#calculateImports() |
| */ |
| protected static void putTypeNameInMap(String typeName, Map typeNameMap) { |
| if ((typeName == null) || typeName.equals("")) { |
| return; |
| } |
| |
| String shortName = shortName(typeName); |
| String packageName = packageName(typeName); |
| |
| if (packageName.length() > 0) { |
| Set packageNames; |
| |
| if (typeNameMap.get(shortName) == null) { |
| packageNames = new HashSet(); |
| typeNameMap.put(shortName, packageNames); |
| } else { |
| packageNames = (Set)typeNameMap.get(shortName); |
| } |
| |
| // There is no package name. The package is the default package. |
| // Do nothing, as neither an import is needed, nor does the class need to be unqualified. |
| if (!packageNames.contains(packageName)) { |
| packageNames.add(packageName); |
| } |
| } |
| } |
| |
| private static String packageName(String typeName) { |
| int lastPeriod = typeName.lastIndexOf('.'); |
| |
| if (lastPeriod == -1) { |
| return ""; |
| } else { |
| return typeName.substring(0, lastPeriod); |
| } |
| } |
| |
| /** |
| * Removes the package name, if there is one. Also removes any trailing brackets. |
| * |
| * Assumes that typeName contains only a package name (optional) and a short name, |
| * potentially with subtended brackets. |
| * |
| * (e.g. {@code int -> int}, {@code java.util.Vector -> Vector}, {@code java.lang.Boolean[] -> Boolean}, etc.) |
| */ |
| private static String shortName(String typeName) { |
| int shortNameStartIndex = typeName.lastIndexOf('.') + 1; |
| int searchIndex = shortNameStartIndex; |
| |
| boolean stillLookingForEnd = true; |
| while (stillLookingForEnd) { |
| if (Character.isJavaIdentifierPart(typeName.charAt(searchIndex))) { |
| searchIndex++; |
| stillLookingForEnd = searchIndex < typeName.length(); |
| } else { |
| stillLookingForEnd = false; |
| } |
| } |
| |
| return typeName.substring(shortNameStartIndex, searchIndex); |
| } |
| |
| public AccessLevel getAccessLevel() { |
| return accessLevel; |
| } |
| |
| public String getComment() { |
| return comment; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public void setAccessLevel(AccessLevel accessLevel) { |
| this.accessLevel = accessLevel; |
| } |
| |
| public void setComment(String comment) { |
| this.comment = comment; |
| } |
| |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| @Override |
| public String toString() { |
| CodeGenerator generator = new CodeGenerator(); |
| write(generator); |
| return generator.toString(); |
| } |
| |
| /** |
| * Write the code out to the generator's stream. |
| */ |
| public void write(CodeGenerator generator) { |
| if (getComment().length() > 0) { |
| generator.writeln("/**"); |
| String comment = getComment(); |
| String cr = org.eclipse.persistence.internal.helper.Helper.cr(); |
| int lastLineIndex = 0; |
| int nextLineIndex = comment.indexOf(cr); |
| while (nextLineIndex != -1) { |
| generator.write(" * "); |
| generator.write(comment.substring(lastLineIndex, nextLineIndex + cr.length())); |
| lastLineIndex = nextLineIndex + cr.length(); |
| nextLineIndex = comment.indexOf(cr, lastLineIndex); |
| } |
| generator.write(" * "); |
| generator.writeln(comment.substring(lastLineIndex, comment.length())); |
| generator.writeln(" */"); |
| generator.cr(); |
| } |
| getAccessLevel().write(generator); |
| generator.write(" "); |
| writeBody(generator); |
| } |
| |
| /** |
| * Write the code out to the generator's stream. |
| */ |
| public abstract void writeBody(CodeGenerator generator); |
| } |