package net.ayld.facade.model;
import com.google.common.collect.ImmutableSet;
import net.ayld.facade.util.Tokenizer;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Meant to represent a fully qualified class name.
*
* The idea behind the class is to provide a model object that makes sure that a string is actually a class name and not
* something else, so one doesn't need to check 'by hand' every time.
* */
public final class ClassName {
/**
* This regex only checks plausibility it doesn't check validity. For a validity check a comparison against Java's reserved words must be made.
* Also checks whether the name contains only Unicode chars.
*
* More info here:
* http://docs.oracle.com/javase/specs/#3.8
*
* */
private final static String CLASS_NAME_VALIDATION_REGEX = "([a-zA-Z_$][a-zA-Z\\d_$]*\\.)*[a-zA-Z_$][a-zA-Z\\d_$]*";
/**
* Class names that are valid classes, but still don't match the above regex.
*
* See here:
* http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javadoc.html#packagecomment
* */
private final static Set<String> EXCEPTIONAL_CLASS_NAMES = ImmutableSet.of(
"package-info"
);
private final String qualifiedClassName;
/**
* Creates a {@link ClassName}.
*
* Doesn't allow nulls or empty strings.
* Does everything it can to make sure that the argument is in fact a fully qualified class name and not something else.
*
* @param qualifiedClassName a class name
* */
public ClassName(String qualifiedClassName) {
if (!isClassName(qualifiedClassName)) {
throw new IllegalArgumentException("invalid fully qualified class name: " + qualifiedClassName + ", expected: " + CLASS_NAME_VALIDATION_REGEX);
}
this.qualifiedClassName = qualifiedClassName;
}
private static boolean isClassName(String qualifiedClassName) {
final String shortName = Tokenizer.delimiter(".").tokenize(qualifiedClassName).lastToken();
return Pattern.matches(CLASS_NAME_VALIDATION_REGEX, qualifiedClassName) || EXCEPTIONAL_CLASS_NAMES.contains(shortName);
}
/**
* Returns the short name of the wrapped qualified class name.
*
* <pre>
*
* In other words for this:
*
* <code>net.ayld.facade.model.ClassName</code>
*
* this method will return:
*
* <code>ClassName</code>
*
* <pre>
*
* @return the short name of the wrapped qualified class name
* */
public String shortName() {
return Tokenizer.delimiter(".").tokenize(qualifiedClassName).lastToken();
}
/**
* Returns the wrapped qualifiedClassName.
*
* @return the wrapped qualifiedClassName
* */
@Override
public String toString() {
return qualifiedClassName;
}
@Override
public int hashCode() {
return qualifiedClassName.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof ClassName)) {
return false;
}
final ClassName other = (ClassName) obj;
return other.toString().equals(this.toString());
}
}