checkModifiable(); final ClassIntrospector newCI = new ClassIntrospector(builder, sharedIntrospectionLock); final ClassIntrospector oldCI; oldCI.unregisterModelFactory(staticModels); staticModels.clearCache(); oldCI.unregisterModelFactory(enumModels); enumModels.clearCache(); oldCI.unregisterModelFactory(modelCache); modelCache.clearCache();
/** * Creates a {@link Map} with the content as described for the return value of {@link #get(Class)}. */ private Map<Object, Object> createClassIntrospectionData(Class<?> clazz) { final Map<Object, Object> introspData = new HashMap<Object, Object>(); if (exposeFields) { addFieldsToClassIntrospectionData(introspData, clazz); } final Map<MethodSignature, List<Method>> accessibleMethods = discoverAccessibleMethods(clazz); addGenericGetToClassIntrospectionData(introspData, accessibleMethods); if (exposureLevel != BeansWrapper.EXPOSE_NOTHING) { try { addBeanInfoToClassIntrospectionData(introspData, clazz, accessibleMethods); } catch (IntrospectionException e) { LOG.warn("Couldn't properly perform introspection for class " + clazz, e); introspData.clear(); // FIXME NBC: Don't drop everything here. } } addConstructorsToClassIntrospectionData(introspData, clazz); if (introspData.size() > 1) { return introspData; } else if (introspData.size() == 0) { return Collections.emptyMap(); } else { // map.size() == 1 Entry<Object, Object> e = introspData.entrySet().iterator().next(); return Collections.singletonMap(e.getKey(), e.getValue()); } }
throws IntrospectionException { BeanInfo beanInfo = Introspector.getBeanInfo(clazz); List<PropertyDescriptor> pdas = getPropertyDescriptors(beanInfo, clazz); int pdasLength = pdas.size(); addPropertyDescriptorToClassIntrospectionData( introspData, pdas.get(i), clazz, accessibleMethods); final MethodAppearanceDecision decision = new MethodAppearanceDecision(); MethodAppearanceDecisionInput decisionInput = null; List<MethodDescriptor> mds = getMethodDescriptors(beanInfo, clazz); sortMethodDescriptors(mds); int mdsSize = mds.size(); IdentityHashMap<Method, Void> argTypesUsedByIndexerPropReaders = null; for (int i = mdsSize - 1; i >= 0; --i) { final Method method = getMatchingAccessibleMethod(mds.get(i).getMethod(), accessibleMethods); if (method != null && isAllowedToExpose(method)) { decision.setDefaults(method); if (methodAppearanceFineTuner != null) { (decision.getReplaceExistingProperty() || !(introspData.get(propDesc.getName()) instanceof FastPropertyDescriptor))) { addPropertyDescriptorToClassIntrospectionData( introspData, propDesc, clazz, accessibleMethods); getArgTypesByMethod(introspData).remove(previous); Class<?>[] replaced = getArgTypesByMethod(introspData).put(method,
void setMethodSorter(MethodSorter methodSorter) { checkModifiable(); if (classIntrospector.getMethodSorter() != methodSorter) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodSorter(methodSorter); replaceClassIntrospector(builder); } }
/** * Used to tweak certain aspects of how methods appear in the data-model; * see {@link MethodAppearanceFineTuner} for more. */ public void setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner) { checkModifiable(); if (classIntrospector.getMethodAppearanceFineTuner() != methodAppearanceFineTuner) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodAppearanceFineTuner(methodAppearanceFineTuner); replaceClassIntrospector(builder); } }
/** * Sets the method exposure level. By default, set to <code>EXPOSE_SAFE</code>. * @param exposureLevel can be any of the <code>EXPOSE_xxx</code> * constants. */ public void setExposureLevel(int exposureLevel) { checkModifiable(); if (classIntrospector.getExposureLevel() != exposureLevel) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposureLevel(exposureLevel); replaceClassIntrospector(builder); } }
/** * Controls whether public instance fields of classes are exposed to * templates. * @param exposeFields if set to true, public instance fields of classes * that do not have a property getter defined can be accessed directly by * their name. If there is a property getter for a property of the same * name as the field (i.e. getter "getFoo()" and field "foo"), then * referring to "foo" in template invokes the getter. If set to false, no * access to public instance fields of classes is given. Default is false. */ public void setExposeFields(boolean exposeFields) { checkModifiable(); if (classIntrospector.getExposeFields() != exposeFields) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposeFields(exposeFields); replaceClassIntrospector(builder); } }
/** * Controls whether Java 8 default methods that weren't overridden in a class will be recognized as bean property * accessors and/or bean actions, and thus will be visible from templates. (We expose bean properties and bean * actions, not methods in general.) Before {@link #getIncompatibleImprovements incompatibleImprovements} 2.3.26 * this defaults to {@code false} for backward compatibility. Starting with {@link #getIncompatibleImprovements * incompatibleImprovements} 2.3.26 it defaults to {@code true}. * <p> * Some explanation: FreeMarker uses {@link java.beans.Introspector} to discover the bean properties and actions of * classes, for maximum conformance to the JavaBeans specification. But for some reason (perhaps just a bug in the * Oracle/OpenJDK Java 8 implementation) that ignores the Java 8 default methods coming from the interfaces. When * this setting is {@code true}, we search for non-overridden default methods ourselves, and add them to the set of * discovered bean members. * * @since 2.3.26 */ public void setTreatDefaultMethodsAsBeanMembers(boolean treatDefaultMethodsAsBeanMembers) { checkModifiable(); if (classIntrospector.getTreatDefaultMethodsAsBeanMembers() != treatDefaultMethodsAsBeanMembers) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setTreatDefaultMethodsAsBeanMembers(treatDefaultMethodsAsBeanMembers); replaceClassIntrospector(builder); } }
onSameNameClassesDetected(className); Map<Object, Object> introspData = createClassIntrospectionData(clazz); synchronized (sharedLock) { cache.put(clazz, introspData);
classIntrospector = new ClassIntrospector( _BeansAPI.getClassIntrospectorBuilder(bwConf), sharedIntrospectionLock); } else { sharedIntrospectionLock = classIntrospector.getSharedLock();
/** * Removes all class introspection data from the cache. * * <p>Use this if you want to free up memory on the expense of recreating * the cache entries for the classes that will be used later in templates. * * @throws IllegalStateException if {@link #isClassIntrospectionCacheRestricted()} is {@code true}. * * @since 2.3.20 */ public void clearClassIntrospecitonCache() { classIntrospector.clearCache(); }
/** * Returns an instance that is possibly shared (singleton). Note that this comes with its own "shared lock", * since everyone who uses this object will have to lock with that common object. */ ClassIntrospector build() { if ((methodAppearanceFineTuner == null || methodAppearanceFineTuner instanceof SingletonCustomizer) && (methodSorter == null || methodSorter instanceof SingletonCustomizer)) { // Instance can be cached. ClassIntrospector instance; synchronized (INSTANCE_CACHE) { Reference instanceRef = (Reference) INSTANCE_CACHE.get(this); instance = instanceRef != null ? (ClassIntrospector) instanceRef.get() : null; if (instance == null) { ClassIntrospectorBuilder thisClone = (ClassIntrospectorBuilder) clone(); // prevent any aliasing issues instance = new ClassIntrospector(thisClone, new Object(), true, true); INSTANCE_CACHE.put(thisClone, new WeakReference(instance, INSTANCE_CACHE_REF_QUEUE)); } } removeClearedReferencesFromInstanceCache(); return instance; } else { // If methodAppearanceFineTuner or methodSorter is specified and isn't marked as a singleton, the // ClassIntrospector can't be shared/cached as those objects could contain a back-reference to the // BeansWrapper. return new ClassIntrospector(this, new Object(), true, false); } }
if (!containsMethodWithSameParameterTypes( defaultMethodsToAddByName.get(introspectorM.getName()), introspectorM)) { newIntrospectionMDs.add(introspectorMD);
void setMethodSorter(MethodSorter methodSorter) { checkModifiable(); if (classIntrospector.getMethodSorter() != methodSorter) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodSorter(methodSorter); replaceClassIntrospector(builder); } }
/** * Used to tweak certain aspects of how methods appear in the data-model; * see {@link MethodAppearanceFineTuner} for more. */ public void setMethodAppearanceFineTuner(MethodAppearanceFineTuner methodAppearanceFineTuner) { checkModifiable(); if (classIntrospector.getMethodAppearanceFineTuner() != methodAppearanceFineTuner) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setMethodAppearanceFineTuner(methodAppearanceFineTuner); replaceClassIntrospector(builder); } }
/** * Sets the method exposure level. By default, set to <code>EXPOSE_SAFE</code>. * @param exposureLevel can be any of the <code>EXPOSE_xxx</code> * constants. */ public void setExposureLevel(int exposureLevel) { checkModifiable(); if (classIntrospector.getExposureLevel() != exposureLevel) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposureLevel(exposureLevel); replaceClassIntrospector(builder); } }
/** * Controls whether public instance fields of classes are exposed to * templates. * @param exposeFields if set to true, public instance fields of classes * that do not have a property getter defined can be accessed directly by * their name. If there is a property getter for a property of the same * name as the field (i.e. getter "getFoo()" and field "foo"), then * referring to "foo" in template invokes the getter. If set to false, no * access to public instance fields of classes is given. Default is false. */ public void setExposeFields(boolean exposeFields) { checkModifiable(); if (classIntrospector.getExposeFields() != exposeFields) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setExposeFields(exposeFields); replaceClassIntrospector(builder); } }
/** * Controls whether Java 8 default methods that weren't overridden in a class will be recognized as bean property * accessors and/or bean actions, and thus will be visible from templates. (We expose bean properties and bean * actions, not methods in general.) Before {@link #getIncompatibleImprovements incompatibleImprovements} 2.3.26 * this defaults to {@code false} for backward compatibility. Starting with {@link #getIncompatibleImprovements * incompatibleImprovements} 2.3.26 it defaults to {@code true}. * <p> * Some explanation: FreeMarker uses {@link java.beans.Introspector} to discover the bean properties and actions of * classes, for maximum conformance to the JavaBeans specification. But for some reason (perhaps just a bug in the * Oracle/OpenJDK Java 8 implementation) that ignores the Java 8 default methods coming from the interfaces. When * this setting is {@code true}, we search for non-overridden default methods ourselves, and add them to the set of * discovered bean members. * * @since 2.3.26 */ public void setTreatDefaultMethodsAsBeanMembers(boolean treatDefaultMethodsAsBeanMembers) { checkModifiable(); if (classIntrospector.getTreatDefaultMethodsAsBeanMembers() != treatDefaultMethodsAsBeanMembers) { ClassIntrospectorBuilder builder = classIntrospector.createBuilder(); builder.setTreatDefaultMethodsAsBeanMembers(treatDefaultMethodsAsBeanMembers); replaceClassIntrospector(builder); } }
onSameNameClassesDetected(className); Map<Object, Object> introspData = createClassIntrospectionData(clazz); synchronized (sharedLock) { cache.put(clazz, introspData);
classIntrospector = new ClassIntrospector( _BeansAPI.getClassIntrospectorBuilder(bwConf), sharedIntrospectionLock); } else { sharedIntrospectionLock = classIntrospector.getSharedLock();