org.nuiton.eugene.java.extension.ImportsManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eugene Show documentation
Show all versions of eugene Show documentation
Efficient Universal Generator.
/*
* #%L
* EUGene :: EUGene
* %%
* Copyright (C) 2004 - 2010 CodeLutin
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.eugene.java.extension;
import org.apache.commons.lang3.StringUtils;
import org.nuiton.eugene.GeneratorUtil;
import org.nuiton.eugene.java.JavaGeneratorUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Class used in generators that allows to manage easily imports. A first-pass
* allow to register imports, and in a second-pass, returns the type to use in
* generated code.
*
* @author athimel (Code Lutin)
* @author Tony Chemit - [email protected]
* @since 2.0.0
*/
public class ImportsManager {
/**
* Internal states of the imports manager.
*
* @see #state
*/
private enum State {
FILLING, READING
}
private static Set primitiveTypes;
static {
primitiveTypes = new HashSet<>();
primitiveTypes.add("byte");
primitiveTypes.add("Byte");
primitiveTypes.add("short");
primitiveTypes.add("Short");
primitiveTypes.add("int");
primitiveTypes.add("Integer");
primitiveTypes.add("long");
primitiveTypes.add("Long");
primitiveTypes.add("float");
primitiveTypes.add("Float");
primitiveTypes.add("double");
primitiveTypes.add("Double");
primitiveTypes.add("char");
primitiveTypes.add("Char");
primitiveTypes.add("String");
primitiveTypes.add("boolean");
primitiveTypes.add("Boolean");
primitiveTypes.add("void");
}
private Map imports = new HashMap<>();
private State state = State.FILLING;
/**
* From the given class, add it to the imports list.
*
* @param clazz the class to import
* @return true if import add was successful
* @see ImportsManager#addImport(String)
*/
public boolean addImport(Class> clazz) {
return addImport(clazz.getName());
}
/**
* From the given fqn (fully qualified name), add it to the imports list.
* If there is a conflict adding this import, will return false.
* If reading of the imports has started, this method will return false,
* unless type does not need to be imported.
*
* @param fqn the fully qualified name to import
* @return true if import add was successful
*/
public boolean addImport(String fqn) {
// don't include null fqn
if (fqn == null) {
return false;
}
int lastDotIndex = getLastDotIndex(fqn);
// if no package don't include it
if (lastDotIndex == -1) {
return true;
}
// Exclude java.lang classes
if (fqn.trim().isEmpty() ||
fqn.startsWith("java.lang.") && lastDotIndex == 9) {
// reacts as if it was imported
return true;
}
// Exclude primitive types
if (primitiveTypes.contains(fqn)) {
// was not imported
return false;
}
if (fqn.endsWith("[]")) {
// fqn contains an array definition
String simpleFQN = fqn.substring(0, fqn.length() - 2);
return addImport(simpleFQN);
}
if (JavaGeneratorUtil.containsGenerics(fqn)) {
// Generics case :
String[] parts = JavaGeneratorUtil.splitGeneric(fqn);
boolean doImport = false;
if (addImport(parts[0])) {
doImport = true;
}
for (int i = 1, partsLength = parts.length; i < partsLength; i++) {
String part = parts[i];
addImport(part);
}
return doImport;
}
// // Reject generics
// if (fqn.contains("<") || fqn.contains(">")) {
// return false;
// }
String name = fqn.substring(lastDotIndex + 1);
String inPlaceFqn = imports.get(name);
if (inPlaceFqn == null) {
// Someone has started to read imports, impossible to add some more
if (state == State.READING) {
return false;
} else {
imports.put(name, fqn);
return true;
}
}
// if fqn is not the same, return false. Otherwise, no need to override.
return inPlaceFqn.equals(fqn);
}
/**
* Accorging to the already added types, returns the type to write in file.
* If there is a conflict, returns the fully qualified name, otherwise
* returns the simple name
*
* @param clazz the clazz to add
* @return the fqn or simple name according to in-place imports
* @since 2.3.2
*/
public String getType(Class> clazz) {
String type = getType(clazz.getName());
return type;
}
/**
* Accorging to the already added types, returns the type to write in file.
* If there is a conflict, returns the fully qualified name, otherwise
* returns the simple name
*
* @param fqn the fully qualified name to add
* @return the fqn or simple name according to in-place imports
*/
public String getType(String fqn) {
boolean importResult = addImport(fqn);
if (JavaGeneratorUtil.containsGenerics(fqn)) {
String[] parts = JavaGeneratorUtil.splitGeneric(fqn);
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
parts[i] = getType(part);
}
return JavaGeneratorUtil.joinGeneric(parts);
}
if (!importResult) {
// There is a conflict, do not use simple name
return fqn;
}
// No conflict, use simple name
int packageEndIndex = getLastDotIndex(fqn);
if (packageEndIndex == -1) {
return fqn;
} else {
return fqn.substring(packageEndIndex + 1);
}
}
public String getReturnType(String returnType) {
if (StringUtils.isBlank(returnType)) {
return null;
}
if (JavaGeneratorUtil.containsGenerics(returnType)) {
// the return type is in two parts : <...> ...
String[] parts =
GeneratorUtil.splitGenericDefinition(returnType);
if (parts.length == 1) {
// no generic definition
return getType(returnType);
}
String genericDef = parts[0];
String strictReturnType = parts[1];
if (StringUtils.isNotBlank(genericDef)) {
genericDef += " ";
}
return genericDef + getType(strictReturnType);
} else {
return getType(returnType);
}
}
/**
* List the imports. This method will remove the useless imports according
* to the given packageName (no need to import a class in the same package)
*
* @param packageName the current package name (to avoid useless imports)
* @return the imports alphabeticaly sorted
*/
public List getImports(String packageName) {
state = State.READING;
List result = new ArrayList<>();
int packageLength = packageName.length();
String packagePrefix = packageName + ".";
for (String fqn : imports.values()) {
int lastDotIndex = getLastDotIndex(fqn);
// only keep sub package of given package
if (!(lastDotIndex == packageLength &&
fqn.startsWith(packagePrefix))) {
result.add(fqn);
}
}
Collections.sort(result);
return result;
}
/**
* Method to reset imports list. If imports has been listed, it becomes back
* possible to add imports.
*/
public void clearImports() {
imports.clear();
state = State.FILLING;
}
/**
* Obtains the last dot index in the given fqn.
*
* @param fqn the fqn to test
* @return the last index of a dot in given fqn
* @since 2.3.2
*/
public int getLastDotIndex(String fqn) {
return fqn.lastIndexOf(".");
}
}