Index: src/testcases/org/apache/poi/TestDeprecatedFeatures.java =================================================================== --- src/testcases/org/apache/poi/TestDeprecatedFeatures.java (revision 0) +++ src/testcases/org/apache/poi/TestDeprecatedFeatures.java (working copy) @@ -0,0 +1,124 @@ +/* ==================================================================== + 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.poi; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Member; +import java.lang.Deprecated; +import java.lang.annotation.Annotation; + +//import org.apache.maven.artifact.versioning.DefaultArtifactVersion; + +import org.apache.poi.util.Removal; + +/** + * Find classes, methods, and field in the POI project that have been deprecated and marked for removal + * Looks for {@literal @}{@link java.lang.Deprecated} and {@literal @}{@link org.apache.poi.util.Removal}. + * + * Unfortunately, a feature that has been {@literal @}deprecated in the JavaDocs cannot be accessed by + * reflection because JavaDocs are not compiled into the final classes. + * Some features may be JavaDoc-deprecated and marked for {@literal @}Removal, but not {@literal @}Deprecated. + * + * + * This class could be used to fail a build if a deprecated feature lingers well after its intended removal + * date. + * + * It may not be possible to remove a deprecated feature if other features that depend on it were not also + * marked for removal. For example, if deprecation and removal annotations were added to an interface but + * not to all implementing classes, we may have to wait another 2 releases to deprecate the forgotten + * features before removing the feature. + * + * For this reason, this unit test should be run in for-info-only mode, and a separate job that is not part + * of the main JDK6-8 builds would be responsible for notifying when features marked for removal are past due. + * + * Based on http://www.vogella.com/tutorials/JavaAnnotations/article.html + */ +public class TestDeprecatedFeatures { + + private static String checkDeprecated(final String message, final AnnotatedElement e) { + final Annotation deprecated = e.getAnnotation(Deprecated.class); + final Removal removal = (Removal) e.getAnnotation(Removal.class); + + if (deprecated == null && removal == null) { + return null; + } + + // compare the current version from build.xml (given by + final String currentVersion = System.getProperty("version.id"); //set by build script (build.xml, build.gradle) + if (currentVersion != null && removal != null) { + final String removalVersion = removal.version(); + if (removalVersion != null) { + // Compare the version numbers with some version-aware string parser + // org.apache.maven.artifact.versioning.ComparableVersion is ASL 2.0-licensed + // org.apache.maven.artifact.versioning.DefaultArtifactVersion + //assertThat(new DefaultArtifactVersion(currentVersion), + // greaterThan(new DefaultArtifactVersion(removalVersion))); + } + } + final String fullName = e.toString(); + final String preamble = message + " [" + fullName + "] "; + + if (deprecated != null && removal != null) { + return preamble + "is deprecated and scheduled for removal in POI " + removal.version(); + } + else if (deprecated != null) { + return preamble + "is deprecated but no scheduled removal version is specified"; + } + else if (removal != null) { + return preamble + "is scheduled for removal in POI " + removal.version(); + } + return null; + } + private static void check(final String message, final AnnotatedElement e) { + String s = checkDeprecated(message, e); + if (s != null) { + System.out.println(s); + } + } + + public static void main(final String[] args) { + Annotation deprecated, removal; + + for (final Class klass : ClassFinder.find("org.apache.poi")) { + // check if the class is deprecated + check("Class", klass); + // inner classes and enums will be checked later by the ClassFinder. + + // check if the class contains any deprecated contructors + for (final Constructor constructor : klass.getDeclaredConstructors()) { + check("Constructor", constructor); + } + + // check if the class contains any deprecated methods + for (final Method method : klass.getDeclaredMethods()) { + check("Method", method); + } + + // check if the class contains any deprecated fields + // https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html + for (final Field field : klass.getDeclaredFields()) { + check("Field", field); + } + + } + } + +} Property changes on: src/testcases/org/apache/poi/TestDeprecatedFeatures.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: src/testcases/org/apache/poi/ClassFinder.java =================================================================== --- src/testcases/org/apache/poi/ClassFinder.java (revision 0) +++ src/testcases/org/apache/poi/ClassFinder.java (working copy) @@ -0,0 +1,53 @@ + +package org.apache.poi; +// NON-FREE! +// Copied from http://stackoverflow.com/questions/15519626/how-to-get-all-classes-names-in-a-package + +import java.io.File; +import java.net.URL; +import java.util.List; +import java.util.ArrayList; + +public class ClassFinder { + + private static final char PKG_SEPARATOR = '.'; + + private static final char DIR_SEPARATOR = '/'; + + private static final String CLASS_FILE_SUFFIX = ".class"; + + private static final String BAD_PACKAGE_ERROR = "Unable to get resources from path '%s'. Are you sure the package '%s' exists?"; + + public static List> find(String scannedPackage) { + String scannedPath = scannedPackage.replace(PKG_SEPARATOR, DIR_SEPARATOR); + URL scannedUrl = Thread.currentThread().getContextClassLoader().getResource(scannedPath); + if (scannedUrl == null) { + throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage)); + } + File scannedDir = new File(scannedUrl.getFile()); + List> classes = new ArrayList>(); + for (File file : scannedDir.listFiles()) { + classes.addAll(find(file, scannedPackage)); + } + return classes; + } + + private static List> find(File file, String scannedPackage) { + List> classes = new ArrayList>(); + String resource = scannedPackage + PKG_SEPARATOR + file.getName(); + if (file.isDirectory()) { + for (File child : file.listFiles()) { + classes.addAll(find(child, resource)); + } + } else if (resource.endsWith(CLASS_FILE_SUFFIX)) { + int endIndex = resource.length() - CLASS_FILE_SUFFIX.length(); + String className = resource.substring(0, endIndex); + try { + classes.add(Class.forName(className)); + } catch (ClassNotFoundException ignore) { + } + } + return classes; + } + +} Property changes on: src/testcases/org/apache/poi/ClassFinder.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: src/java/org/apache/poi/util/Removal.java =================================================================== --- src/java/org/apache/poi/util/Removal.java (revision 1783736) +++ src/java/org/apache/poi/util/Removal.java (working copy) @@ -58,4 +58,6 @@ * Example: "3.15" */ String version() default ""; + // TODO: Verify that the version syntax is valid by parsing with a version-aware parser like + // org.apache.maven.artifact.versioning.DefaultArtifactVersion } Index: src/testcases/org/apache/poi/TestTestDeprecatedFeatures.java =================================================================== --- src/testcases/org/apache/poi/TestTestDeprecatedFeatures.java (revision 0) +++ src/testcases/org/apache/poi/TestTestDeprecatedFeatures.java (working copy) @@ -0,0 +1,75 @@ +/* ==================================================================== + 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.poi; + +import java.lang.Deprecated; + + +import org.apache.poi.util.Removal; + +/** + * A test class to verify that TestDeprecatedFeatures can find all the known deprecation types + * with different visibility. + */ +@Deprecated +@Removal(version="3.14") +public class TestTestDeprecatedFeatures { + @Deprecated + @Removal(version="3.14") + private static final int CLASS_CONST = 5; + + @Deprecated + @Removal(version="3.14") + protected int FIELD = 5; + + @Deprecated + @Removal(version="3.14") + public TestTestDeprecatedFeatures() { + } + + @Deprecated + @Removal(version="3.14") + public class SomeDeprecatedInner { + @Deprecated + @Removal(version="3.14") + private SomeDeprecatedInner() { + } + } + + // enums are a special case of class and will be recognized as a class with reflection + @Deprecated + @Removal(version="3.14") + /*package*/ enum SomeDeprecatedEnum { + MERCURY, + VENUS, + EARTH, + MARS, + JUPITER, + SATURN, + URANUS, + NEPTUNE, + @Deprecated + @Removal(version="3.14") + PLUTO + } + + @Deprecated + @Removal(version="3.14") + public void someDeprecatedMethod() { + } +} Property changes on: src/testcases/org/apache/poi/TestTestDeprecatedFeatures.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property