blob: f4ae7c24e1f03fb6f44d7c0829d61deb0ffb1934 [file] [log] [blame]
/*
* 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<String, Set<String>> typeNameMap) {
if ((typeName == null) || typeName.equals("")) {
return false;
}
if (packageName(typeName).length() == 0) {
return false;
}
Set<String> packages = 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 -&gt; int, java.util.Vector -&gt; Vector, java.lang.Boolean[] -&gt; Boolean[], etc.)
*/
protected static String adjustTypeName(String typeName, Map<String, Set<String>> 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<String> parseForTypeNames(String longString) {
Set<String> 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<String> parseForTypeNamesInPackage(String longString, String packageName) {
Set<String> 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<String, Set<String>> typeNameMap) {
if ((typeName == null) || typeName.equals("")) {
return;
}
String shortName = shortName(typeName);
String packageName = packageName(typeName);
if (packageName.length() > 0) {
Set<String> packageNames;
if (typeNameMap.get(shortName) == null) {
packageNames = new HashSet<>();
typeNameMap.put(shortName, packageNames);
} else {
packageNames = 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));
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);
}