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

org.jboss.jandex.DotName Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2013 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed 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.jboss.jandex;

import java.util.ArrayDeque;

/**
 * A DotName represents a dot separated name, typically a Java package or a Java class.
 * It has two possible variants. A simple wrapper based variant allows for fast construction
 * (it simply wraps the specified name string). Whereas, a componentized variant represents
 * one or more String methodInternal that when combined with a dot character, assemble the full
 * name. The intention of the componentized variant is that the String methodInternal can be reused
 * to offer memory efficiency. This reuse is common in Java where packages and classes follow
 * a tree structure.
 *
 * 

Both the simple and componentized variants are considered semantically equivalent if they * refer to the same logical name. More specifically the equals and hashCode methods return the * same values for the same semantic name regardless of the variant used. Which variant to use * when depends on the specific performance and overhead objectives of the specific use pattern. * *

Simple names are cheap to construct (just a an additional wrapper object), so are ideal for * temporary use, like looking for an entry in a Map. Componentized names however require that * they be split in advance, and so require some additional time to construct. However the memory * benefits of reusing component strings make them desirable when stored in a longer term area * such as in a Java data structure. * * @author Jason T. Greene * */ public final class DotName implements Comparable { static final DotName JAVA_NAME; static final DotName JAVA_LANG_NAME; static final DotName OBJECT_NAME; private final DotName prefix; private final String local; private int hash; private boolean componentized = false; private boolean innerClass = false; static { JAVA_NAME = new DotName(null, "java", true, false); JAVA_LANG_NAME = new DotName(JAVA_NAME, "lang", true, false); OBJECT_NAME = new DotName(JAVA_LANG_NAME, "Object", true, false); } /** * Constructs a simple DotName which stores the string in it's entirety. This variant is ideal * for temporary usage, such as looking up an entry in a Map. * * @param name A fully qualified non-null name (with dots) * @return a simple DotName that wraps name */ public static DotName createSimple(String name) { return new DotName(null, name, false, false); } /** * Constructs a componentized DotName. Each DotName refers to a parent * prefix (or null if there is no further prefix) in addition to a local * name that has no dot separator. The fully qualified name this DotName * represents is consructed by recursing all parent prefixes and joining all * local name values with the '.' character. * * @param prefix Another DotName that is the portion to the left of * localName, this may be null if there is not one * @param localName the local non-null portion of this name, which does not contain * '.' * @return a componentized DotName. */ public static DotName createComponentized(DotName prefix, String localName) { if (localName.indexOf('.') != -1) throw new IllegalArgumentException("A componentized DotName can not contain '.' characters in a local name"); return new DotName(prefix, localName, true, false); } /** * Constructs a componentized DotName. Each DotName refers to a parent * prefix (or null if there is no further prefix) in addition to a local * name that has no dot separator. The fully qualified name this DotName * represents is consructed by recursing all parent prefixes and joining all * local name values with the '.' character. * * @param prefix Another DotName that is the portion to the left of * localName, this may be null if there is not one * @param localName the local non-null portion of this name, which does not contain * '.' * @param innerClass whether or not this localName is an inner class name, requiring '$' vs '.' * @return a componentized DotName. */ public static DotName createComponentized(DotName prefix, String localName, boolean innerClass) { if (localName.indexOf('.') != -1) throw new IllegalArgumentException("A componentized DotName can not contain '.' characters in a local name"); return new DotName(prefix, localName, true, innerClass); } DotName(DotName prefix, String local, boolean noDots, boolean innerClass) { if (local == null) { throw new IllegalArgumentException("Local string can not be null"); } if (prefix != null && !prefix.componentized) { throw new IllegalArgumentException("A componentized DotName must have a componentized prefix, or null"); } this.prefix = prefix; this.local = local; this.componentized = noDots; this.innerClass = innerClass; } /** * Returns the parent prefix for this DotName or null if there is none. * Simple DotName variants never have a prefix. * * @return the parent prefix for this DotName */ public DotName prefix() { return prefix; } /** * Returns the local portion of this DotName. In simple variants, the entire fully qualified * string is returned. In componentized variants, just the right most portion not including a separator * is returned. * * @return the non-null local portion of this DotName */ public String local() { return local; } /** * Returns whether this DotName is a componentized variant. * * @return true if it is componentized, false if it is a simple DotName */ public boolean isComponentized() { return componentized; } /** * Returns whether the local portion of this DotName represents an inner class. * * @return true if local is an inner class name, false otherwise */ public boolean isInner() { return innerClass; } /** * Returns the regular fully qualifier class name. * * @return The fully qualified class name */ public String toString() { return toString('.'); } public String toString(char delim) { String string = local; if (prefix != null) { StringBuilder builder = new StringBuilder(); builder.append(prefix.toString(delim)).append(innerClass ? '$' : delim).append(string); string = builder.toString(); } return string; } /** * Returns a hash code which is based on the semantic representation of this DotName. * Whether or not a DotName is componentized has no impact on the calculated hash code. * * @return a hash code representing this object * @see Object#hashCode() */ public int hashCode() { int hash = this.hash; if (hash != 0) return hash; if (prefix != null) { hash = prefix.hashCode() * 31 + (innerClass ? '$' : '.'); // Luckily String.hashCode documents the algorithm it follows for (int i = 0; i < local.length(); i++) { hash = 31 * hash + local.charAt(i); } } else { hash = local.hashCode(); } return this.hash = hash; } /** * Compares a DotName to another DotName and returns whether this DotName * is lesser than, greater than, or equal to the specified DotName. If this DotName is lesser, * a negative value is returned. If greater, a positive value is returned. If equal, zero is returned. * * @param other the DotName to compare to * @return a negative number if this is less than the specified object, a positive if greater, and zero if equal * * @see Comparable#compareTo(Object) */ @Override public int compareTo(DotName other) { if (componentized && other.componentized) { ArrayDeque thisStack = new ArrayDeque(); ArrayDeque otherStack = new ArrayDeque(); DotName curr = this; while (curr != null) { thisStack.push(curr); curr = curr.prefix(); } curr = other; while (curr != null) { otherStack.push(curr); curr = curr.prefix(); } int thisSize = thisStack.size(); int otherSize = otherStack.size(); int stop = Math.min(thisSize, otherSize); for (int i = 0; i < stop; i++) { DotName thisComp = thisStack.pop(); DotName otherComp = otherStack.pop(); int comp = thisComp.local.compareTo(otherComp.local); if (comp != 0) return comp; } int diff = thisSize - otherSize; if (diff != 0) return diff; } // Fallback to string comparison return toString().compareTo(other.toString()); } /** * Compares a DotName to another DotName and returns true if the represent * the same underlying semantic name. In other words, whether or not a * name is componentized or simple has no bearing on the comparison. * * @param o the DotName object to compare to * @return true if equal, false if not * * @see Object#equals(Object) */ public boolean equals(Object o) { if (this == o) return true; if (! (o instanceof DotName)) return false; DotName other = (DotName)o; if (other.prefix == null && prefix == null) return local.equals(other.local) && innerClass == other.innerClass; if (!other.componentized && componentized) return toString().equals(other.local); if (other.componentized && !componentized) return other.toString().equals(local); return local.equals(other.local) && prefix.equals(other.prefix) && innerClass == other.innerClass; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy