001package com.avaje.ebean.config; 002 003 004/** 005 * Helper to find classes taking into account the context class loader. 006 */ 007public class ClassLoadConfig { 008 009 protected final ClassLoaderContext context; 010 011 /** 012 * Construct with the default classLoader search with context classLoader first. 013 */ 014 public ClassLoadConfig() { 015 this(null); 016 } 017 018 /** 019 * Specify the classLoader to use for class detection and new instance creation. 020 */ 021 public ClassLoadConfig(ClassLoader classLoader) { 022 this.context = new ClassLoaderContext(classLoader); 023 } 024 025 /** 026 * Return true if the Java.time types are available and should be supported. 027 */ 028 public boolean isJavaTimePresent() { 029 return isPresent("java.time.LocalDate"); 030 } 031 032 /** 033 * Return true if the Joda types are available and should be supported. 034 */ 035 public boolean isJodaTimePresent() { 036 return isPresent("org.joda.time.LocalDateTime"); 037 } 038 039 /** 040 * Return true if javax validation annotations like Size and NotNull are present. 041 */ 042 public boolean isJavaxValidationAnnotationsPresent() { 043 return isPresent("javax.validation.constraints.NotNull"); 044 } 045 046 /** 047 * Return true if Jackson annotations like JsonIgnore are present. 048 */ 049 public boolean isJacksonAnnotationsPresent() { 050 return isPresent("com.fasterxml.jackson.annotation.JsonIgnore"); 051 } 052 053 /** 054 * Return true if Jackson ObjectMapper is present. 055 */ 056 public boolean isJacksonObjectMapperPresent() { 057 return isPresent("com.fasterxml.jackson.databind.ObjectMapper"); 058 } 059 060 /** 061 * Return a new instance of the class using the default constructor. 062 */ 063 public Object newInstance(String className) { 064 065 try { 066 Class<?> cls = forName(className); 067 return cls.newInstance(); 068 } catch (Exception e) { 069 throw new IllegalArgumentException("Error constructing " + className, e); 070 } 071 } 072 073 /** 074 * Return true if the given class is present. 075 */ 076 protected boolean isPresent(String className) { 077 try { 078 forName(className); 079 return true; 080 } catch (Throwable ex) { 081 // Class or one of its dependencies is not present... 082 return false; 083 } 084 } 085 086 /** 087 * Load a class taking into account a context class loader (if present). 088 */ 089 protected Class<?> forName(String name) throws ClassNotFoundException { 090 return context.forName(name); 091 } 092 093 /** 094 * Return the classLoader to use for service loading etc. 095 */ 096 public ClassLoader getClassLoader() { 097 return context.getClassLoader(); 098 } 099 100 /** 101 * Wraps the preferred, caller and context class loaders. 102 */ 103 protected class ClassLoaderContext { 104 105 /** 106 * Optional - if set only use this classLoader (no fallback). 107 */ 108 protected final ClassLoader preferredLoader; 109 110 protected final ClassLoader contextLoader; 111 112 protected final ClassLoader callerLoader; 113 114 ClassLoaderContext(ClassLoader preferredLoader) { 115 this.preferredLoader = preferredLoader; 116 this.callerLoader = ServerConfig.class.getClassLoader(); 117 this.contextLoader = contextLoader(); 118 } 119 120 ClassLoader contextLoader() { 121 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 122 return (loader != null) ? loader: callerLoader; 123 } 124 125 Class<?> forName(String name) throws ClassNotFoundException { 126 127 if (preferredLoader != null) { 128 // only use the explicitly set classLoader 129 return classForName(name, preferredLoader); 130 } 131 try { 132 // try the context loader first 133 return classForName(name, contextLoader); 134 } catch (ClassNotFoundException e) { 135 if (callerLoader == contextLoader) { 136 throw e; 137 } else { 138 // fallback to the caller classLoader 139 return classForName(name, callerLoader); 140 } 141 } 142 } 143 144 Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException { 145 return Class.forName(name, true, classLoader); 146 } 147 148 ClassLoader getClassLoader() { 149 return preferredLoader != null ? preferredLoader : contextLoader; 150 } 151 } 152} 153