All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cayenne.gen.ImportUtils Maven / Gradle / Ivy

/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 ****************************************************************/

package org.apache.cayenne.gen;

import org.apache.cayenne.util.Util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Methods for mangling strings.
 * 
 */
public class ImportUtils {

	public static final String importOrdering[] = new String[] { "java.", "javax.", "org.", "com." };

	static final String primitives[] = new String[] { "long", "double", "byte", "boolean", "float", "short", "int",
			"char" };

	static final String primitiveClasses[] = new String[] { Long.class.getName(), Double.class.getName(),
			Byte.class.getName(), Boolean.class.getName(), Float.class.getName(), Short.class.getName(),
			Integer.class.getName(), Character.class.getName() };

	static Map classesForPrimitives = Util.toMap(primitives, primitiveClasses);
	static Map primitivesForClasses = Util.toMap(primitiveClasses, primitives);

	protected Map importTypesMap = new HashMap<>();

	// Types forced to be FQN
	protected Map reservedImportTypesMap = new HashMap<>();

	protected String packageName;

	public ImportUtils() {
		super();
	}

	protected boolean canRegisterType(String typeName) {
		// Not sure why this would ever happen, but it did
		if (null == typeName)
			return false;

		StringUtils stringUtils = StringUtils.getInstance();
		String typeClassName = stringUtils.stripPackageName(typeName);
		String typePackageName = stringUtils.stripClass(typeName);

		if (typePackageName.length() == 0)
			return false; // disallow non-packaged types (primitives, probably)
		if ("java.lang".equals(typePackageName))
			return false;

		// Can only have one type -- rest must use fqn
		if (reservedImportTypesMap.containsKey(typeClassName))
			return false;
		if (importTypesMap.containsKey(typeClassName))
			return false;

		return true;
	}

	/**
	 * Reserve a fully-qualified data type class name so it cannot be used by
	 * another class. No import statements will be generated for reserved types.
	 * Typically, this is the fully-qualified class name of the class being
	 * generated.
	 * 
	 * @param typeName
	 *            FQ data type class name.
	 */
	public void addReservedType(String typeName) {
		if (!canRegisterType(typeName))
			return;

		StringUtils stringUtils = StringUtils.getInstance();
		String typeClassName = stringUtils.stripPackageName(typeName);

		reservedImportTypesMap.put(typeClassName, typeName);
	}

	/**
	 * Register a fully-qualified data type class name. For example,
	 * org.apache.cayenne.CayenneDataObject.
	 * 
	 * @param typeName
	 *            FQ data type class name.
	 */
	public void addType(String typeName) {
		if (!canRegisterType(typeName))
			return;

		StringUtils stringUtils = StringUtils.getInstance();
		String typePackageName = stringUtils.stripClass(typeName);
		String typeClassName = stringUtils.stripPackageName(typeName);

		if (typePackageName.equals(packageName))
			return;

		importTypesMap.put(typeClassName, typeName);
	}

	/**
	 * Add the package name to use for this importUtil invocation.
	 * 
	 * @param packageName
	 */
	public void setPackage(String packageName) {
		this.packageName = packageName;
	}

	/**
	 * Performs processing similar to formatJavaType(String), with
	 * special handling of primitive types and their Java class counterparts.
	 * This method allows users to make a decision whether to use primitives or
	 * not, regardless of how type is mapped.
	 */
	public String formatJavaType(String typeName, boolean usePrimitives) {
		if (usePrimitives) {
			String primitive = primitivesForClasses.get(typeName);
			return (primitive != null) ? primitive : formatJavaType(typeName);
		} else {
			String primitiveClass = classesForPrimitives.get(typeName);
			return (primitiveClass != null) ? formatJavaType(primitiveClass) : formatJavaType(typeName);
		}
	}

	/**
	 * Removes registered package and non-reserved registered type name prefixes
	 * from java types
	 */
	public String formatJavaType(String typeName) {
		if (typeName != null) {
			StringUtils stringUtils = StringUtils.getInstance();
			String typeClassName = stringUtils.stripPackageName(typeName);

			if (!reservedImportTypesMap.containsKey(typeClassName)) {
				if (importTypesMap.containsKey(typeClassName)) {
					if (typeName.equals(importTypesMap.get(typeClassName)))
						return typeClassName;
				}
			}

			String typePackageName = stringUtils.stripClass(typeName);
			if ("java.lang".equals(typePackageName))
				return typeClassName;
			if ((null != packageName) && (packageName.equals(typePackageName)))
				return typeClassName;
		}

		return typeName;
	}

	/**
	 * @since 3.0
	 */
	public String formatJavaTypeAsNonBooleanPrimitive(String type) {
		String value = ImportUtils.classesForPrimitives.get(type);
		return formatJavaType(value != null ? value : type);
	}

	/**
	 * @since 3.0
	 */
	public boolean isNonBooleanPrimitive(String type) {
		return ImportUtils.classesForPrimitives.containsKey(type) && !isBoolean(type);
	}

	/**
	 * @since 3.0
	 */
	public boolean isBoolean(String type) {
		return "boolean".equals(type);
	}

	/**
	 * Generate package and list of import statements based on the registered
	 * types.
	 */
	public String generate() {
		StringBuilder outputBuffer = new StringBuilder();

		if (null != packageName) {
			outputBuffer.append("package ");
			outputBuffer.append(packageName);

			// Using UNIX line endings intentionally - generated Java files
			// should look
			// the same regardless of platform to prevent developer teams
			// working on
			// multiple OS's to override each other's work
			outputBuffer.append(";\n\n");
		}

		List typesList = new ArrayList<>(importTypesMap.values());
		Collections.sort(typesList, new Comparator() {

			public int compare(String s1, String s2) {

				for (String ordering : importOrdering) {
					if ((s1.startsWith(ordering)) && (!s2.startsWith(ordering))) {
						return -1;
					}
					if ((!s1.startsWith(ordering)) && (s2.startsWith(ordering))) {
						return 1;
					}
				}

				return s1.compareTo(s2);
			}
		});

		String lastStringPrefix = null;
		boolean firstIteration = true;
		for (String typeName : typesList) {

			if (firstIteration) {
				firstIteration = false;
			} else {
				outputBuffer.append('\n');
			}
			// Output another newline if we're in a different root package.
			// Find root package
			String thisStringPrefix = typeName;
			int dotIndex = typeName.indexOf('.');
			if (-1 != dotIndex) {
				thisStringPrefix = typeName.substring(0, dotIndex);
			}
			// if this isn't the first import,
			if (null != lastStringPrefix) {
				// and it's different from the last import
				if (false == thisStringPrefix.equals(lastStringPrefix)) {
					// output a newline; force UNIX style per comment above
					outputBuffer.append("\n");
				}
			}
			lastStringPrefix = thisStringPrefix;

			outputBuffer.append("import ");
			outputBuffer.append(typeName);
			outputBuffer.append(';');
		}

		return outputBuffer.toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy