简体   繁体   中英

How can I check if a class belongs to Java JDK

I use an external library which return some List<?> . I need to check if each object of this list is an Object of the JDK (String, int, Integer...). Is this a proper solution?

List<?> list = externalLibrary.search(...);
for(clazz : list) {
    if (clazz.getPackage().getName().startsWith("java.lang"))
      // do something different
}

Is there a better one?

Depending on your definition of "object of the JDK" -- which could get quite fuzzy around the edges -- no, this isn't going to do it. The java.lang package is only a tiny part of all the classes included in the JDK.

You might check whether each object was loaded by the same ClassLoader that loaded java.lang.String -- ie,

if (theObject.getClass().getClassLoader() == "".getClass().getClassLoader()) ...

In general, a different ClassLoader will be used for system classes vs. application classes.

It is probably OK, just you have to check the following packages:

java
javax
com.sun
sun

probably others...

We use the below class to check if the classes belongs to JDK

public class JDKClass {

    private static Set<String> CS = new HashSet<String>();

    static {
        try {
            File file = new File(System.getProperty("java.home"),
                    "lib/classlist");
            BufferedReader r = new BufferedReader(new FileReader(file));
            String l;
            while (true) {
                l = r.readLine();
                if (l == null) {
                    break;
                } else {
                    CS.add(l.replace('/', '.'));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean contains(String o) {
        return CS.contains(o) || o.startsWith("java") || o.startsWith("com.sun")
                || o.startsWith("sun") || o.startsWith("oracle")
                || o.startsWith("org.xml") || o.startsWith("com.oracle");
    }

    private JDKClass() {
    }

}

You can use ClassLoader.getSystemResources and then check from what jar is the class loaded (fg if it comes from rt.jar).

You will get URL's such as:

jar:file:/C:/Users/user/.m2/repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class

Example code taken from SLF4j:

  private static String STATIC_LOGGER_BINDER_PATH = 
     "org/slf4j/impl/StaticLoggerBinder.class";
  private static void singleImplementationSanityCheck() {
    try {
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class
          .getClassLoader();
      Enumeration paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader
            .getResources(STATIC_LOGGER_BINDER_PATH);
      }
  List implementationList = new ArrayList();
  while (paths.hasMoreElements()) {
    URL path = (URL) paths.nextElement();
    implementationList.add(path);
  }
    ....
  }

I think an easier solution is to thing of the problem this way: write a method to identify all classes that are defined by you. In most cases, all user defined classes follow a pattern like com.something.something. Then if they do not belong to com.something.something, it is a JDK class

Personally I like class loader base answer. But it will return true also on StringBuilder. If you want to more narrow definition that is only "built-in" types, you can try to evaluate whether this is primitive type (such as int) or wrapper type (such as Integer) or String. You can write something like this:

    import java.util.Map;
    import java.util.TreeMap;



    public class Utils {

        private static Map<String, Class<?>> SUBST_MAP = new TreeMap<String, Class<?>>();
        private static Map<String, Class<?>> SIMPLE_MAP = new TreeMap<String, Class<?>>();


        static {
            SUBST_MAP.put(Byte.class.getName(), Byte.TYPE);
            SUBST_MAP.put(Short.class.getName(), Short.TYPE);
            SUBST_MAP.put(Integer.class.getName(), Integer.TYPE);
            SUBST_MAP.put(Long.class.getName(), Long.TYPE);
            SUBST_MAP.put(Float.class.getName(), Float.TYPE);
            SUBST_MAP.put(Double.class.getName(), Double.TYPE);
            SUBST_MAP.put(Boolean.class.getName(), Boolean.TYPE);
            SUBST_MAP.put(Character.class.getName(), Character.TYPE);
            SIMPLE_MAP.put(String.class.getName(), Boolean.TRUE);

        }




    /**
     * Gets the the class type of the types of the argument.
     * 
     * if substPrimitiveWrapper is true,
     * then if there is argument, that represent primitive type wrapper (such as Integer),
     *      then it will be substituted to primitive type (such as int).
     * else no substitution will be done.
     *
     * @param arg object.
     * @param substPrimitiveWrapper - wheteher to do primitive type substitution.
     * @retrun class type.
     */

    public static Class<?> getClassType(Object arg, boolean substPrimitiveWrapper){
        Class<?> classType = null;
        String className = null;
        Class<?> substClass = null;

        if(arg != null ){
            //making default classType
            classType = arg.getClass();
            if(substPrimitiveWrapper){
                className = classType.getName();
                substClass = (Class<?>)SUBST_MAP.get(className);
                if(substClass != null){
                    classType = substClass;
                }

            }
        }
        return classType;
    }

    /**
     * This method consider JDK type any primitive type, wrapper class or String.
     * 
     * 
     * @param arg object
     * @return where arg is JDK type or now.
     */
    public static boolean isJDKClass(Object arg){
        Class<?> classType = getClassType(arg, true);
        boolean isJDKClass = false;
        if(classType!=null){
            //if(String.class.equals(classType)){
            //  isJDKClass = true; //this is String, note that String is final
            //}
            assert classType!=null;
            String className = classType.getName();
            Boolean isFound = (Boolean)SIMPLE_MAP.get(className);
            if(Boolean.TRUE.equals(isFound)){
                isJDKClass = true; //this is predefined class
            }


            boolean isPrimitiveType = classType.isPrimitive();
            if(isPrimitiveType){
                isJDKClass = true; //this is primitive type or wrapper class
            }
        }

        return isJDKClass;
     }

    } 

You can also optionally add support for such classes like java.math.BigDecimal , java.util.Date , java.sql.Timestamp . Note, however, that they are not final, so I assumed that if somebody extended them even in the trivial way, it will not be considered as JDK class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM