net.sf.qualitytest.StaticCheck Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2013 André Rouél and Dominik Seichter
*
* 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 net.sf.qualitytest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import javax.annotation.Nonnull;
import net.sf.qualitycheck.Check;
import net.sf.qualitycheck.Throws;
import net.sf.qualitycheck.exception.IllegalNullArgumentException;
import net.sf.qualitytest.exception.IllegalClassWithPublicDefaultConstructorException;
import net.sf.qualitytest.exception.IllegalMissingAnnotationOnMethodException;
import net.sf.qualitytest.exception.IllegalNonFinalClassException;
import net.sf.qualitytest.exception.IllegalNonFinalStaticException;
/**
* This class offers simple static methods to test static properties of your classes.
*
* These checks are typically only called from within unit tests, because they are costly. Static tests in unit tests
* ensure that certain intended properties of a class (e.g. immutability, thread-safeness, no non static finals, etc.)
* are still true after future changes.
*
* @author Dominik Seichter
*/
public final class StaticCheck {
/**
* Check if a class is final.
*
* @param clazz
* A class that must be final.
* @return clazz The class that was passed to this method.
*
* @throws IllegalNonFinalClassException
* If the passed class is not final.
*/
public static Class> classIsFinal(@Nonnull final Class> clazz) {
final boolean isFinal = ModifierBits.isModifierBitSet(clazz.getModifiers(), Modifier.FINAL);
if (!isFinal) {
throw new IllegalNonFinalClassException(clazz.getName());
}
return clazz;
}
/**
* Checks if a field is static and not final according to its modifiers. *
*
* @param f
* a java Field
* @return true if the field is static but is not final
*/
private static boolean isStaticAndNotFinal(final Field f) {
final int modifiers = f.getModifiers();
final boolean isStatic = ModifierBits.isModifierBitSet(modifiers, Modifier.STATIC);
final boolean isFinal = ModifierBits.isModifierBitSet(modifiers, Modifier.FINAL);
return isStatic && !isFinal;
}
/**
* Check if a class contains a non-final static variable. Non-final static fields are dangerous in multi-threaded
* environments and should therefore not be used.
*
* This method only checks the passed class and not any super-classes.
*
* @param clazz
* A class which is checked for non-final statics.
* @return clazz The class that was passed to this method.
*
* @throws IllegalNonFinalStaticException
* If the passed class contains and non-final static field.
*/
public static Class> noNonFinalStatic(@Nonnull final Class> clazz) {
final Field[] fields = clazz.getDeclaredFields();
for (final Field f : fields) {
if (!f.isSynthetic() && isStaticAndNotFinal(f)) {
throw new IllegalNonFinalStaticException(clazz.getName(), f.getName());
}
}
return clazz;
}
/**
* Check if a class or super-class contains a non-final static variable. Non-final static fields are dangerous in
* multi-threaded environments and should therefore not be used.
*
* @param clazz
* A class which is checked for non-final statics.
* @return clazz The class that was passed to this method.
*
* @throws IllegalNonFinalStaticException
* If the passed class contains and non-final static field.
*/
public static Class> noNonFinalStaticInHierarchy(@Nonnull final Class> clazz) {
Class> obj = clazz;
do {
StaticCheck.noNonFinalStatic(obj);
obj = obj.getSuperclass();
} while (obj != null);
return clazz;
}
/**
* Check that a class contains no public default constructor. It is recommended to hide the public default
* constructor of utility classes by providing a private default construct.
*
* This method assures that the given class cannot be intantiated
*
* @param clazz
* A class which is checked for not having a public default constructor
* @return clazz The class that was passed to this method.
*
* @throws IllegalClassWithPublicDefaultConstructorException
* If the passed class contains a public default constructor.
*/
public static Class> noPublicDefaultConstructor(@Nonnull final Class> clazz) {
try {
clazz.newInstance();
throw new IllegalClassWithPublicDefaultConstructorException(clazz.getName());
} catch (final InstantiationException e) {
throw new IllegalClassWithPublicDefaultConstructorException(clazz.getName(), e);
} catch (final IllegalAccessException e) {
// This the exception we want.
return clazz;
}
}
/**
* Check that all declared public methods of a class are annotated using a certain annotation.
*
* @param clazz
* A class that must have annotations on all public methods.
* @param annotation
* An annotation that must be present on all public methods in a class
* @return the checked class
*
* @throws IllegalMissingAnnotationOnMethodException
* if the one or more public methods of a {@link Class} are not annotated with a specific
* {@link Annotation}
*/
@Throws( { IllegalNullArgumentException.class, IllegalMissingAnnotationOnMethodException.class })
public static Class> publicMethodsAnnotated(@Nonnull final Class> clazz, @Nonnull final Class extends Annotation> annotation) {
Check.notNull(clazz);
Check.notNull(annotation);
final Method[] methods = clazz.getDeclaredMethods();
for (final Method m : methods) {
if (Modifier.isPublic(m.getModifiers()) && !m.isAnnotationPresent(annotation)) {
throw new IllegalMissingAnnotationOnMethodException(clazz, annotation, m);
}
}
return clazz;
}
/**
* Attention: This class is not intended to create objects from it.
*/
private StaticCheck() {
// This class is not intended to create objects from it.
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy