Instruction:
作为 Java 安全专家，检测此代码中的安全漏洞：
## 内容1
### 文件路径：
impl/src/main/java/com/sun/faces/application/applicationimpl/InstanceFactory.java
### 代码内容：
package com.sun.faces.application.applicationimpl;

import static com.sun.faces.application.ApplicationImpl.THIS_LIBRARY;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.DateTimeConverterUsesSystemTimezone;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.RegisterConverterPropertyEditors;
import static com.sun.faces.util.Util.isEmpty;
import static com.sun.faces.util.Util.loadClass;
import static com.sun.faces.util.Util.notNull;
import static com.sun.faces.util.Util.notNullNamedObject;
import static java.beans.Introspector.getBeanInfo;
import static java.beans.PropertyEditorManager.findEditor;
import static java.text.MessageFormat.format;
import static java.util.Collections.unmodifiableMap;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import static javax.faces.application.Resource.COMPONENT_RESOURCE_KEY;
import static javax.faces.component.UIComponent.ATTRS_WITH_DECLARED_DEFAULT_VALUES;
import static javax.faces.component.UIComponent.BEANINFO_KEY;
import static javax.faces.component.UIComponent.COMPOSITE_COMPONENT_TYPE_KEY;

import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.enterprise.inject.spi.BeanManager;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.Resource;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.Behavior;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.DateTimeConverter;
import javax.faces.el.ValueBinding;
import javax.faces.render.RenderKit;
import javax.faces.render.Renderer;
import javax.faces.validator.Validator;
import javax.faces.view.ViewDeclarationLanguage;

import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.application.ConverterPropertyEditorFactory;
import com.sun.faces.application.ViewMemberInstanceFactoryMetadataMap;
import com.sun.faces.cdi.CdiUtils;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.MessageUtils;
import com.sun.faces.util.ReflectionUtils;
import com.sun.faces.util.Util;

public class InstanceFactory {

    // Log instance for this class
    private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();

    private static final String CONTEXT = "context";
    private static final String COMPONENT_EXPRESSION = "componentExpression";
    private static final String COMPONENT_TYPE = "componentType";
    private static final String COMPONENT_CLASS = "componentClass";

    private static final Map<String, Class<?>[]> STANDARD_CONV_ID_TO_TYPE_MAP = new HashMap<>(8, 1.0f);
    private static final Map<Class<?>, String> STANDARD_TYPE_TO_CONV_ID_MAP = new HashMap<>(16, 1.0f);

    static {
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Byte", new Class[] { Byte.TYPE, Byte.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Boolean", new Class[] { Boolean.TYPE, Boolean.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Character", new Class[] { Character.TYPE, Character.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Short", new Class[] { Short.TYPE, Short.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Integer", new Class[] { Integer.TYPE, Integer.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Long", new Class[] { Long.TYPE, Long.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Float", new Class[] { Float.TYPE, Float.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("javax.faces.Double", new Class[] { Double.TYPE, Double.class });
        for (Map.Entry<String, Class<?>[]> entry : STANDARD_CONV_ID_TO_TYPE_MAP.entrySet()) {
            Class<?>[] types = entry.getValue();
            String key = entry.getKey();
            for (Class<?> clazz : types) {
                STANDARD_TYPE_TO_CONV_ID_MAP.put(clazz, key);
            }
        }
    }

    private final String[] STANDARD_BY_TYPE_CONVERTER_CLASSES = { "java.math.BigDecimal", "java.lang.Boolean", "java.lang.Byte", "java.lang.Character",
            "java.lang.Double", "java.lang.Float", "java.lang.Integer", "java.lang.Long", "java.lang.Short", "java.lang.Enum" };

    private Map<Class<?>, Object> converterTypeMap;
    private boolean registerPropertyEditors;
    private boolean passDefaultTimeZone;

    private TimeZone systemTimeZone;

    private static final class ComponentResourceClassNotFound{}

    //
    // These four maps store store "identifier" | "class name"
    // mappings.
    //
    private ViewMemberInstanceFactoryMetadataMap<String, Object> componentMap;
    private ViewMemberInstanceFactoryMetadataMap<String, Object> behaviorMap;
    private ViewMemberInstanceFactoryMetadataMap<String, Object> converterIdMap;
    private ViewMemberInstanceFactoryMetadataMap<String, Object> validatorMap;

    private Set<String> defaultValidatorIds;
    private volatile Map<String, String> defaultValidatorInfo;

    private final ApplicationAssociate associate;
    private Version version;

    /**
     * Stores the bean manager.
     */
    private BeanManager beanManager;

    public InstanceFactory(ApplicationAssociate applicationAssociate) {
        this.associate = applicationAssociate;
        version = new Version();

        componentMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());
        converterIdMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());
        converterTypeMap = new ConcurrentHashMap<>();
        validatorMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());
        defaultValidatorIds = new LinkedHashSet<>();
        behaviorMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());

        WebConfiguration webConfig = WebConfiguration.getInstance(FacesContext.getCurrentInstance().getExternalContext());
        registerPropertyEditors = webConfig.isOptionEnabled(RegisterConverterPropertyEditors);

        passDefaultTimeZone = webConfig.isOptionEnabled(DateTimeConverterUsesSystemTimezone);
        if (passDefaultTimeZone) {
            systemTimeZone = TimeZone.getDefault();
        }
    }

    /**
     * @see javax.faces.application.Application#addComponent(java.lang.String, java.lang.String)
     */
    public void addComponent(String componentType, String componentClass) {

        notNull(COMPONENT_TYPE, componentType);
        notNull(COMPONENT_CLASS, componentClass);

        if (LOGGER.isLoggable(FINE) && componentMap.containsKey(componentType)) {
            LOGGER.log(FINE, "componentType {0} has already been registered.  Replacing existing component class type {1} with {2}.",
                    new Object[] { componentType, componentMap.get(componentType), componentClass });
        }

        componentMap.put(componentType, componentClass);

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("added component of type ''{0}'' and class ''{1}''", componentType, componentClass));
        }
    }

    public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType) throws FacesException {

        notNull(COMPONENT_EXPRESSION, componentExpression);
        notNull(CONTEXT, context);
        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(context, componentExpression, componentType, null, true);
    }

    public UIComponent createComponent(String componentType) throws FacesException {

        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(FacesContext.getCurrentInstance(), componentType, null, true);
    }

    public UIComponent createComponent(FacesContext context, Resource componentResource, ExpressionFactory expressionFactory) throws FacesException {

        // RELEASE_PENDING (rlubke,driscoll) this method needs review.

        notNull(CONTEXT, context);
        notNull("componentResource", componentResource);

        UIComponent result = null;

        // Use the application defined in the FacesContext as we may be calling
        // overriden methods
        Application app = context.getApplication();

        ViewDeclarationLanguage vdl = app.getViewHandler().getViewDeclarationLanguage(context, context.getViewRoot().getViewId());
        BeanInfo componentMetadata = vdl.getComponentMetadata(context, componentResource);

        if (componentMetadata != null) {
            BeanDescriptor componentBeanDescriptor = componentMetadata.getBeanDescriptor();

            // Step 1. See if the composite component author explicitly
            // gave a componentType as part of the composite component metadata
            ValueExpression valueExpression = (ValueExpression) componentBeanDescriptor.getValue(COMPOSITE_COMPONENT_TYPE_KEY);

            if (valueExpression != null) {
                String componentType = (String) valueExpression.getValue(context.getELContext());
                if (!isEmpty(componentType)) {
                    result = app.createComponent(componentType);
                }
            }
        }

        // Step 2. If that didn't work, if a script based resource can be
        // found for the scriptComponentResource, see if a component can be generated from it
        if (result == null) {
            Resource scriptComponentResource = vdl.getScriptComponentResource(context, componentResource);

            if (scriptComponentResource != null) {
                result = createComponentFromScriptResource(context, scriptComponentResource, componentResource);
            }
        }

        // Step 3. Use the libraryName of the resource as the java package
        // and use the resourceName as the class name. See
        // if a Java class can be loaded
        if (result == null) {
            String packageName = componentResource.getLibraryName();
            String className = componentResource.getResourceName();
            className = packageName + '.' + className.substring(0, className.lastIndexOf('.'));
            try {
                Class<?> clazz = (Class<?>) componentMap.get(className);
                if (clazz == null) {
                    clazz = loadClass(className, this);
                }
                if (clazz != ComponentResourceClassNotFound.class) {
                    if (!associate.isDevModeEnabled()) {
                        componentMap.put(className, clazz);
                    }
                    result = (UIComponent) clazz.newInstance();
                }
            } catch (ClassNotFoundException ex) {
                if (!associate.isDevModeEnabled()) {
                    componentMap.put(className, ComponentResourceClassNotFound.class);
                }
            } catch (InstantiationException | IllegalAccessException | ClassCastException ie) {
                throw new FacesException(ie);
            }
        }

        // Step 4. Use javax.faces.NamingContainer as the component type
        if (result == null) {
            result = app.createComponent("javax.faces.NamingContainer");
        }

        result.setRendererType("javax.faces.Composite");

        Map<String, Object> attrs = result.getAttributes();
        attrs.put(COMPONENT_RESOURCE_KEY, componentResource);
        attrs.put(BEANINFO_KEY, componentMetadata);

        associate.getAnnotationManager().applyComponentAnnotations(context, result);
        pushDeclaredDefaultValuesToAttributesMap(context, componentMetadata, attrs, result, expressionFactory);

        return result;
    }

    public UIComponent createComponent(FacesContext context, String componentType, String rendererType) {
        return createComponentApplyAnnotations(context, componentType, rendererType, true);
    }

    public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType, String rendererType) {

        notNull(COMPONENT_EXPRESSION, componentExpression);
        notNull(CONTEXT, context);
        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(context, componentExpression, componentType, rendererType, true);
    }

    public UIComponent createComponent(ValueBinding componentBinding, FacesContext context, String componentType) throws FacesException {

        notNull("componentBinding", componentBinding);
        notNull(CONTEXT, context);
        notNull(COMPONENT_TYPE, componentType);

        Object result;
        boolean createOne = false;
        try {
            result = componentBinding.getValue(context);
            if (result != null) {
                createOne = !(result instanceof UIComponent);
            }

            if (result == null || createOne) {
                result = createComponentApplyAnnotations(context, componentType, null, false);
                componentBinding.setValue(context, result);
            }
        } catch (Exception ex) {
            throw new FacesException(ex);
        }

        return (UIComponent) result;
    }

    /**
     * @see javax.faces.application.Application#getComponentTypes()
     */
    public Iterator<String> getComponentTypes() {
        return componentMap.keySet().iterator();
    }

    /**
     * @see javax.faces.application.Application#addBehavior(String, String)
     */
    public void addBehavior(String behaviorId, String behaviorClass) {

        notNull("behaviorId", behaviorId);
        notNull("behaviorClass", behaviorClass);

        if (LOGGER.isLoggable(FINE) && behaviorMap.containsKey(behaviorId)) {
            LOGGER.log(FINE, "behaviorId {0} has already been registered.  Replacing existing behavior class type {1} with {2}.",
                    new Object[] { behaviorId, behaviorMap.get(behaviorId), behaviorClass });
        }

        behaviorMap.put(behaviorId, behaviorClass);

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("added behavior of type ''{0}'' class ''{1}''", behaviorId, behaviorClass));
        }
    }

    /**
     * @see javax.faces.application.Application#createBehavior(String)
     */
    public Behavior createBehavior(String behaviorId) throws FacesException {

        notNull("behaviorId", behaviorId);

        Behavior behavior = createCDIBehavior(behaviorId);
        if (behavior != null) {
            return behavior;
        }

        behavior = newThing(behaviorId, behaviorMap);

        notNullNamedObject(behavior, behaviorId, "jsf.cannot_instantiate_behavior_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("created behavior of type ''{0}''", behaviorId));
        }

        associate.getAnnotationManager().applyBehaviorAnnotations(FacesContext.getCurrentInstance(), behavior);

        return behavior;
    }

    /**
     * @see javax.faces.application.Application#getBehaviorIds()
     */
    public Iterator<String> getBehaviorIds() {
        return behaviorMap.keySet().iterator();
    }

    public void addConverter(String converterId, String converterClass) {

        notNull("converterId", converterId);
        notNull("converterClass", converterClass);

        if (LOGGER.isLoggable(FINE) && converterIdMap.containsKey(converterId)) {
            LOGGER.log(FINE, "converterId {0} has already been registered.  Replacing existing converter class type {1} with {2}.",
                    new Object[] { converterId, converterIdMap.get(converterId), converterClass });
        }

        converterIdMap.put(converterId, converterClass);

        Class<?>[] types = STANDARD_CONV_ID_TO_TYPE_MAP.get(converterId);
        if (types != null) {
            for (Class<?> clazz : types) {
                // go directly against map to prevent cyclic method calls
                converterTypeMap.put(clazz, converterClass);
                addPropertyEditorIfNecessary(clazz);
            }
        }

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(format("added converter of type ''{0}'' and class ''{1}''", converterId, converterClass));
        }
    }

    /**
     * @see javax.faces.application.Application#addConverter(Class, String)
     */
    public void addConverter(Class<?> targetClass, String converterClass) {

        notNull("targetClass", targetClass);
        notNull("converterClass", converterClass);

        String converterId = STANDARD_TYPE_TO_CONV_ID_MAP.get(targetClass);
        if (converterId != null) {
            addConverter(converterId, converterClass);
        } else {
            if (LOGGER.isLoggable(FINE) && converterTypeMap.containsKey(targetClass)) {
                LOGGER.log(FINE, "converter target class {0} has already been registered.  Replacing existing converter class type {1} with {2}.",
                        new Object[] { targetClass.getName(), converterTypeMap.get(targetClass), converterClass });
            }

            converterTypeMap.put(targetClass, converterClass);
            addPropertyEditorIfNecessary(targetClass);
        }

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(format("added converter of class type ''{0}''", converterClass));
        }
    }

    /**
     * @see javax.faces.application.Application#createConverter(String)
     */
    public Converter<?> createConverter(String converterId) {

        notNull("converterId", converterId);

        Converter<?> converter = createCDIConverter(converterId);
        if (converter != null) {
            return converter;
        }

        converter = newThing(converterId, converterIdMap);

        notNullNamedObject(converter, converterId, "jsf.cannot_instantiate_converter_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("created converter of type ''{0}''", converterId));
        }

        if (passDefaultTimeZone && converter instanceof DateTimeConverter) {
            ((DateTimeConverter) converter).setTimeZone(systemTimeZone);
        }

        associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), converter);

        return converter;
    }

    /**
     * @see javax.faces.application.Application#createConverter(Class)
     */
    public Converter createConverter(Class<?> targetClass) {

        Util.notNull("targetClass", targetClass);
        Converter returnVal = null;

        if (version.isJsf23()) {
            BeanManager beanManager = getBeanManager();
            returnVal = CdiUtils.createConverter(beanManager, targetClass);
            if (returnVal != null) {
                return returnVal;
            }
        }

        returnVal = (Converter) newConverter(targetClass, converterTypeMap, targetClass);
        if (returnVal != null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
            }
            if (passDefaultTimeZone && returnVal instanceof DateTimeConverter) {
                ((DateTimeConverter) returnVal).setTimeZone(systemTimeZone);
            }
            associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), returnVal);
            return returnVal;
        }

        // Search for converters registered to interfaces implemented by
        // targetClass
        Class<?>[] interfaces = targetClass.getInterfaces();
        if (interfaces != null) {
            for (int i = 0; i < interfaces.length; i++) {
                returnVal = createConverterBasedOnClass(interfaces[i], targetClass);
                if (returnVal != null) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
                    }
                    if (passDefaultTimeZone && returnVal instanceof DateTimeConverter) {
                        ((DateTimeConverter) returnVal).setTimeZone(systemTimeZone);
                    }
                    associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), returnVal);
                    return returnVal;
                }
            }
        }

        // Search for converters registered to superclasses of targetClass
        Class<?> superclass = targetClass.getSuperclass();
        if (superclass != null) {
            returnVal = createConverterBasedOnClass(superclass, targetClass);
            if (returnVal != null) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
                }
                if (passDefaultTimeZone && returnVal instanceof DateTimeConverter) {
                    ((DateTimeConverter) returnVal).setTimeZone(systemTimeZone);
                }
                associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), returnVal);
                return returnVal;
            }
        }

        return returnVal;
    }

    /**
     * @see javax.faces.application.Application#getConverterIds()
     */
    public Iterator<String> getConverterIds() {
        return converterIdMap.keySet().iterator();

    }

    /**
     * @see javax.faces.application.Application#getConverterTypes()
     */
    public Iterator<Class<?>> getConverterTypes() {
        return converterTypeMap.keySet().iterator();
    }

    /**
     * @see javax.faces.application.Application#addValidator(String, String)
     */
    public void addValidator(String validatorId, String validatorClass) {

        Util.notNull("validatorId", validatorId);
        Util.notNull("validatorClass", validatorClass);

        if (LOGGER.isLoggable(Level.FINE) && validatorMap.containsKey(validatorId)) {
            LOGGER.log(Level.FINE, "validatorId {0} has already been registered.  Replacing existing validator class type {1} with {2}.",
                    new Object[] { validatorId, validatorMap.get(validatorId), validatorClass });
        }

        validatorMap.put(validatorId, validatorClass);

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine(MessageFormat.format("added validator of type ''{0}'' class ''{1}''", validatorId, validatorClass));
        }

    }

    /**
     * @see javax.faces.application.Application#createValidator(String)
     */
    public Validator<?> createValidator(String validatorId) throws FacesException {

        notNull("validatorId", validatorId);

        Validator<?> validator = createCDIValidator(validatorId);
        if (validator != null) {
            return validator;
        }

        validator = newThing(validatorId, validatorMap);

        notNullNamedObject(validator, validatorId, "jsf.cannot_instantiate_validator_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("created validator of type ''{0}''", validatorId));
        }

        associate.getAnnotationManager().applyValidatorAnnotations(FacesContext.getCurrentInstance(), validator);

        return validator;
    }

    /**
     * @see javax.faces.application.Application#getValidatorIds()
     */
    public Iterator<String> getValidatorIds() {
        return validatorMap.keySet().iterator();
    }

    /**
     * @see javax.faces.application.Application#addDefaultValidatorId(String)
     */
    public synchronized void addDefaultValidatorId(String validatorId) {

        notNull("validatorId", validatorId);

        defaultValidatorInfo = null;
        defaultValidatorIds.add(validatorId);
    }

    /**
     * @see javax.faces.application.Application#getDefaultValidatorInfo()
     */
    public Map<String, String> getDefaultValidatorInfo() {

        if (defaultValidatorInfo == null) {
            synchronized (this) {
                if (defaultValidatorInfo == null) {
                    defaultValidatorInfo = new LinkedHashMap<>();
                    if (!defaultValidatorIds.isEmpty()) {
                        for (String id : defaultValidatorIds) {
                            String validatorClass;
                            Object result = validatorMap.get(id);
                            if (null != result) {
                                if (result instanceof Class) {
                                    validatorClass = ((Class) result).getName();
                                } else {
                                    validatorClass = result.toString();
                                }
                                defaultValidatorInfo.put(id, validatorClass);
                            }
                        }

                    }
                }
            }
            defaultValidatorInfo = unmodifiableMap(defaultValidatorInfo);
        }

        return defaultValidatorInfo;

    }

    // --------------------------------------------------------- Private Methods

    private UIComponent createComponentFromScriptResource(FacesContext context, Resource scriptComponentResource, Resource componentResource) {

        UIComponent result = null;

        String className = scriptComponentResource.getResourceName();
        int lastDot = className.lastIndexOf('.');
        className = className.substring(0, lastDot);

        try {

            Class<?> componentClass = (Class<?>) componentMap.get(className);
            if (componentClass == null) {
                componentClass = Util.loadClass(className, this);
            }
            if (!associate.isDevModeEnabled()) {
                componentMap.put(className, componentClass);
            }
            result = (UIComponent) componentClass.newInstance();
        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException ex) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE, null, ex);
            }
        }

        if (result != null) {
            // Make sure the resource is there for the annotation processor.
            result.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, componentResource);
            // In case there are any "this" references,
            // make sure they can be resolved.
            context.getAttributes().put(THIS_LIBRARY, componentResource.getLibraryName());
            try {
                associate.getAnnotationManager().applyComponentAnnotations(context, result);
            } finally {
                context.getAttributes().remove(THIS_LIBRARY);
            }
        }

        return result;

    }

    /**
     * Leveraged by
     * {@link Application#createComponent(javax.el.ValueExpression, javax.faces.context.FacesContext, String)}
     * and
     * {@link Application#createComponent(javax.el.ValueExpression, javax.faces.context.FacesContext, String, String)}.
     * This method will apply any component and render annotations that may be present.
     */
    private UIComponent createComponentApplyAnnotations(FacesContext ctx, ValueExpression componentExpression, String componentType, String rendererType,
            boolean applyAnnotations) {

        UIComponent c;

        try {
            c = (UIComponent) componentExpression.getValue(ctx.getELContext());

            if (c == null) {
                c = this.createComponentApplyAnnotations(ctx, componentType, rendererType, applyAnnotations);
                componentExpression.setValue(ctx.getELContext(), c);
            } else if (applyAnnotations) {
                this.applyAnnotations(ctx, rendererType, c);
            }
        } catch (Exception ex) {
            throw new FacesException(ex);
        }

        return c;

    }

    /**
     * Leveraged by {@link Application#createComponent(String)} and
     * {@link Application#createComponent(javax.faces.context.FacesContext, String, String)} This
     * method will apply any component and render annotations that may be present.
     */
    private UIComponent createComponentApplyAnnotations(FacesContext ctx, String componentType, String rendererType, boolean applyAnnotations) {

        UIComponent component;
        try {
            component = newThing(componentType, componentMap);
        } catch (Exception ex) {
            if (LOGGER.isLoggable(SEVERE)) {
                LOGGER.log(Level.SEVERE, "jsf.cannot_instantiate_component_error", componentType);
            }
            throw new FacesException(ex);
        }

        notNullNamedObject(component, componentType, "jsf.cannot_instantiate_component_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.log(FINE, MessageFormat.format("Created component with component type of ''{0}''", componentType));
        }

        if (applyAnnotations) {
            applyAnnotations(ctx, rendererType, component);
        }

        return component;
    }

    /**
     * Process any annotations associated with this component/renderer.
     */
    private void applyAnnotations(FacesContext ctx, String rendererType, UIComponent c) {

        if (c != null && ctx != null) {
            associate.getAnnotationManager().applyComponentAnnotations(ctx, c);
            if (rendererType != null) {
                RenderKit rk = ctx.getRenderKit();
                Renderer r = null;
                if (rk != null) {
                    r = rk.getRenderer(c.getFamily(), rendererType);
                    if (r != null) {
                        c.setRendererType(rendererType);
                        associate.getAnnotationManager().applyRendererAnnotations(ctx, r, c);
                    }
                }
                if ((rk == null || r == null) && LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.log(Level.FINE, "Unable to create Renderer with rendererType {0} for component with component type of {1}",
                            new Object[] { rendererType, c.getFamily() });
                }
            }
        }
    }

    /**
     * <p>
     * PRECONDITIONS: the values in the Map are either Strings representing fully qualified java
     * class names, or java.lang.Class instances.
     * </p>
     * <p>
     * ALGORITHM: Look in the argument map for a value for the argument key. If found, if the value
     * is instanceof String, assume the String specifies a fully qualified java class name and
     * obtain the java.lang.Class instance for that String using Util.loadClass(). Replace the
     * String instance in the argument map with the Class instance. If the value is instanceof
     * Class, proceed. Assert that the value is either instanceof java.lang.Class or
     * java.lang.String.
     * </p>
     * <p>
     * Now that you have a java.lang.class, call its newInstance and return it as the result of this
     * method.
     * </p>
     *
     * @param key Used to look up the value in the <code>Map</code>.
     * @param map The <code>Map</code> that will be searched.
     * @return The new object instance.
     */
    @SuppressWarnings("unchecked")
    private <T> T newThing(String key, ViewMemberInstanceFactoryMetadataMap<String, Object> map) {

        Object result;
        Class<?> clazz;
        Object value;

        value = map.get(key);
        if (value == null) {
            return null;
        }
        assert value instanceof String || value instanceof Class;
        if (value instanceof String) {
            String cValue = (String) value;
            try {
                clazz = Util.loadClass(cValue, value);
                if (!associate.isDevModeEnabled()) {
                    map.put(key, clazz);
                }
                assert clazz != null;
            } catch (Exception e) {
                throw new FacesException(e.getMessage(), e);
            }
        } else {
            clazz = (Class) value;
        }

        try {
            result = clazz.newInstance();
        } catch (Throwable t) {
            Throwable previousT;
            do {
                previousT = t;
                if (LOGGER.isLoggable(Level.SEVERE)) {
                    LOGGER.log(Level.SEVERE, "Unable to load class: ", t);
                }
            } while (null != (t = t.getCause()));
            t = previousT;

            throw new FacesException(MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID, clazz.getName()), t);
        }

        return (T) result;
    }

    /*
     * This method makes it so that any cc:attribute elements that have a "default" attribute value
     * have those values pushed into the composite component attribute map so that programmatic
     * access (as opposed to EL access) will find the attribute values.
     *
     */
    @SuppressWarnings("unchecked")
    private void pushDeclaredDefaultValuesToAttributesMap(FacesContext context, BeanInfo componentMetadata, Map<String, Object> attrs, UIComponent component, ExpressionFactory expressionFactory) {

        Collection<String> attributesWithDeclaredDefaultValues = null;
        PropertyDescriptor[] propertyDescriptors = null;

        for (PropertyDescriptor propertyDescriptor : componentMetadata.getPropertyDescriptors()) {
            Object defaultValue = propertyDescriptor.getValue("default");

            if (defaultValue != null) {
                String key = propertyDescriptor.getName();
                boolean isLiteralText = false;

                if (defaultValue instanceof ValueExpression) {
                    isLiteralText = ((ValueExpression) defaultValue).isLiteralText();
                    if (isLiteralText) {
                        defaultValue = ((ValueExpression) defaultValue).getValue(context.getELContext());
                    }
                }

                // Ensure this attribute is not a method-signature. method-signature
                // declared default values are handled in retargetMethodExpressions.
                if (propertyDescriptor.getValue("method-signature") == null || propertyDescriptor.getValue("type") != null) {

                    if (attributesWithDeclaredDefaultValues == null) {
                        BeanDescriptor beanDescriptor = componentMetadata.getBeanDescriptor();
                        attributesWithDeclaredDefaultValues = (Collection<String>) beanDescriptor.getValue(ATTRS_WITH_DECLARED_DEFAULT_VALUES);
                        if (attributesWithDeclaredDefaultValues == null) {
                            attributesWithDeclaredDefaultValues = new HashSet<>();
                            beanDescriptor.setValue(ATTRS_WITH_DECLARED_DEFAULT_VALUES, attributesWithDeclaredDefaultValues);
                        }
                    }
                    attributesWithDeclaredDefaultValues.add(key);

                    // Only store the attribute if it is literal text. If it
                    // is a ValueExpression, it will be handled explicitly in
                    // CompositeComponentAttributesELResolver.ExpressionEvalMap.get().
                    // If it is a MethodExpression, it will be dealt with in
                    // retargetMethodExpressions.
                    if (isLiteralText) {
                        try {
                            if (propertyDescriptors == null) {
                                propertyDescriptors = getBeanInfo(component.getClass()).getPropertyDescriptors();
                            }
                        } catch (IntrospectionException e) {
                            throw new FacesException(e);
                        }

                        defaultValue = convertValueToTypeIfNecessary(key, defaultValue, propertyDescriptors, expressionFactory);
                        attrs.put(key, defaultValue);
                    }
                }
            }
        }
    }

    /**
     * Helper method to convert a value to a type as defined in PropertyDescriptor(s)
     *
     * @param name
     * @param value
     * @param propertyDescriptors
     * @return value
     */
    private Object convertValueToTypeIfNecessary(String name, Object value, PropertyDescriptor[] propertyDescriptors, ExpressionFactory expressionFactory) {
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            if (propertyDescriptor.getName().equals(name)) {
                value = expressionFactory.coerceToType(value, propertyDescriptor.getPropertyType());
                break;
            }
        }

        return value;
    }

    /**
     * <p>
     * To enable EL Coercion to use JSF Custom converters, this method will call
     * <code>PropertyEditorManager.registerEditor()</code>, passing the
     * <code>ConverterPropertyEditor</code> class for the <code>targetClass</code> if the target
     * class is not one of the standard by-type converter target classes.
     *
     * @param targetClass the target class for which a PropertyEditory may or may not be created
     */
    private void addPropertyEditorIfNecessary(Class<?> targetClass) {

        if (!registerPropertyEditors) {
            return;
        }

        PropertyEditor editor = findEditor(targetClass);
        if (editor != null) {
            return;
        }
        String className = targetClass.getName();

        // Don't add a PropertyEditor for the standard by-type converters.
        if (targetClass.isPrimitive()) {
            return;
        }

        for (String standardClass : STANDARD_BY_TYPE_CONVERTER_CLASSES) {
            if (standardClass.indexOf(className) != -1) {
                return;
            }
        }

        Class<?> editorClass = ConverterPropertyEditorFactory.getDefaultInstance().definePropertyEditorClassFor(targetClass);
        if (editorClass != null) {
            PropertyEditorManager.registerEditor(targetClass, editorClass);
        } else {
            if (LOGGER.isLoggable(WARNING)) {
                LOGGER.warning(MessageFormat.format("definePropertyEditorClassFor({0}) returned null.", targetClass.getName()));
            }
        }
    }

    private Converter createConverterBasedOnClass(Class<?> targetClass, Class<?> baseClass) {

        Converter returnVal = (Converter) newConverter(targetClass, converterTypeMap, baseClass);
        if (returnVal != null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
            }
            return returnVal;
        }

        // Search for converters registered to interfaces implemented by
        // targetClass
        Class<?>[] interfaces = targetClass.getInterfaces();
        if (interfaces != null) {
            for (int i = 0; i < interfaces.length; i++) {
                returnVal = createConverterBasedOnClass(interfaces[i], null);
                if (returnVal != null) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
                    }
                    return returnVal;
                }
            }
        }

        // Search for converters registered to superclasses of targetClass
        Class<?> superclass = targetClass.getSuperclass();
        if (superclass != null) {
            returnVal = createConverterBasedOnClass(superclass, targetClass);
            if (returnVal != null) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
                }
                return returnVal;
            }
        }
        return returnVal;
    }

    /**
     * <p>
     * The same as newThing except that a single argument constructor that accepts a Class is looked
     * for before calling the no-arg version.
     * </p>
     *
     * <p>
     * PRECONDITIONS: the values in the Map are either Strings representing fully qualified java
     * class names, or java.lang.Class instances.
     * </p>
     * <p>
     * ALGORITHM: Look in the argument map for a value for the argument key. If found, if the value
     * is instanceof String, assume the String specifies a fully qualified java class name and
     * obtain the java.lang.Class instance for that String using Util.loadClass(). Replace the
     * String instance in the argument map with the Class instance. If the value is instanceof
     * Class, proceed. Assert that the value is either instanceof java.lang.Class or
     * java.lang.String.
     * </p>
     * <p>
     * Now that you have a java.lang.class, call its newInstance and return it as the result of this
     * method.
     * </p>
     *
     * @param key Used to look up the value in the <code>Map</code>.
     * @param map The <code>Map</code> that will be searched.
     * @param targetClass the target class for the single argument ctor
     * @return The new object instance.
     */
    protected Object newConverter(Class<?> key, Map<Class<?>, Object> map, Class<?> targetClass) {
        assert key != null && map != null;

        Object result = null;
        Class<?> clazz;
        Object value;

        value = map.get(key);
        if (value == null) {
            return null;
        }
        assert value instanceof String || value instanceof Class;
        if (value instanceof String) {
            String cValue = (String) value;
            try {
                clazz = Util.loadClass(cValue, value);
                if (!associate.isDevModeEnabled()) {
                    map.put(key, clazz);
                }
                assert clazz != null;
            } catch (Exception e) {
                throw new FacesException(e.getMessage(), e);
            }
        } else {
            clazz = (Class) value;
        }

        Constructor ctor = ReflectionUtils.lookupConstructor(clazz, Class.class);
        Throwable cause = null;
        if (ctor != null) {
            try {
                result = ctor.newInstance(targetClass);
            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                cause = e;
            }
        } else {
            try {
                result = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                cause = e;
            }
        }

        if (null != cause) {
            throw new FacesException(MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID, clazz.getName()), cause);

        }
        return result;
    }

    /**
     * Get the bean manager.
     *
     * @return the bean manager.
     */
    private BeanManager getBeanManager() {
        if (beanManager == null) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            beanManager = Util.getCdiBeanManager(facesContext);
        }
        return beanManager;
    }

    private Behavior createCDIBehavior(String behaviorId) {
        if (version.isJsf23()) {
            return CdiUtils.createBehavior(getBeanManager(), behaviorId);
        }

        return null;
    }

    private Converter<?> createCDIConverter(String converterId) {
        if (version.isJsf23()) {
            return CdiUtils.createConverter(getBeanManager(), converterId);
        }

        return null;
    }

    private Validator<?> createCDIValidator(String validatorId) {
        if (version.isJsf23()) {
            return CdiUtils.createValidator(getBeanManager(), validatorId);
        }

        return null;
    }

}

## 内容2
### 文件路径：
impl/src/main/java/com/sun/faces/application/resource/ResourceManager.java
### 代码内容：
package com.sun.faces.application.resource;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Stream;

import javax.faces.application.ProjectStage;
import javax.faces.application.ResourceHandler;
import javax.faces.application.ResourceVisitOption;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

import com.sun.faces.config.WebConfiguration;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.Util;

/**
 * This class is used to lookup {@link ResourceInfo} instances
 * and cache any that are successfully looked up to reduce the
 * computational overhead with the scanning/version checking.
 *
 * @since 2.0
 */
public class ResourceManager {

    private static final Logger LOGGER = FacesLogger.RESOURCE.getLogger();

    /**
     * {@link Pattern} for valid mime types to configure compression.
     */
    private static final Pattern CONFIG_MIMETYPE_PATTERN = Pattern.compile("[a-z-]*/[a-z0-9.\\*-]*");

    private FaceletWebappResourceHelper faceletWebappResourceHelper = new FaceletWebappResourceHelper();

    /**
     * {@link ResourceHelper} used for looking up webapp-based resources.
     */
    private ResourceHelper webappResourceHelper = new WebappResourceHelper();

    /**
     * {@link ResourceHelper} used for looking up classpath-based resources.
     */
    private ClasspathResourceHelper classpathResourceHelper = new ClasspathResourceHelper();

    /**
     * Cache for storing {@link ResourceInfo} instances to reduce the cost
     * of the resource lookups.
     */
    private ResourceCache cache;

    /**
     * Patterns used to find {@link ResourceInfo} instances that may have their
     * content compressed.
     */
    private List<Pattern> compressableTypes;

    /**
     * This lock is used to ensure the lookup of compressable {@link ResourceInfo}
     * instances are atomic to prevent theading issues when writing the compressed
     * content during a lookup.
     */
    private ReentrantLock lock = new ReentrantLock();

    // ------------------------------------------------------------ Constructors

    /*
     * This ctor is only ever called by test code.
     */

    public ResourceManager(ResourceCache cache) {
        this.cache = cache;
        Map<String, Object> throwAwayMap = new HashMap<>();
        initCompressableTypes(throwAwayMap);
    }

    /**
     * Constructs a new <code>ResourceManager</code>.  Note:  if the current
     * {@link ProjectStage} is {@link ProjectStage#Development} caching or
     * {@link ResourceInfo} instances will not occur.
     */
    public ResourceManager(Map<String, Object> appMap, ResourceCache cache) {
        this.cache = cache;
        initCompressableTypes(appMap);
    }

    // ------------------------------------------------------ Public Methods

    /**
     * <p>
     * Attempt to lookup a {@link ResourceInfo} based on the specified
     * <code>libraryName<code> and <code>resourceName</code>
     * </p>
     *
     * <p>
     * Implementation Note:  Synchronization is necessary when looking up
     * compressed resources.  This ensures the atomicity of the content
     * being compressed.  As such, the cost of doing this is low as once
     * the resource is in the cache, the lookup won't be performed again
     * until the cache is cleared.  That said, it's not a good idea
     * to have caching disabled in a production environment if leveraging
     * compression.
     *
     * If the resource isn't compressable, then we don't worry about creating
     * a few extra copies of ResourceInfo until the cache is populated.
     * </p>
     *
     * @param libraryName the name of the library (if any)
     * @param resourceName the name of the resource
     * @param contentType the content type of the resource.  This will be
     *  used to determine if the resource is compressable
     * @param ctx the {@link javax.faces.context.FacesContext} for the current
     *  request
     *
     * @return a {@link ResourceInfo} if a resource if found matching the
     *  provided arguments, otherwise, return <code>null</code>
     */
    public ResourceInfo findResource(String libraryName, String resourceName, String contentType, FacesContext ctx) {
        return findResource(libraryName, resourceName, contentType, false, ctx);
    }

    public ResourceInfo findViewResource(String resourceName, String contentType, FacesContext facesContext) {
        String localePrefix = getLocalePrefix(facesContext);
        List<String> contracts = getResourceLibraryContracts(facesContext);

        ResourceInfo info = getFromCache(resourceName, null, localePrefix, contracts);

        if (info == null) {
            if (isCompressable(contentType, facesContext)) {
                info = findResourceCompressed(null, resourceName, true, localePrefix, contracts, facesContext);
            } else {
               info = findResourceNonCompressed(null, resourceName, true, localePrefix, contracts, facesContext);
            }
        }

        return info;
    }

    public ResourceInfo findResource(String libraryName, String resourceName, String contentType, boolean isViewResource, FacesContext ctx) {

        String localePrefix = getLocalePrefix(ctx);
        List<String> contracts = getResourceLibraryContracts(ctx);

        ResourceInfo info = getFromCache(resourceName, libraryName, localePrefix, contracts);

        if (info == null) {
            if (isCompressable(contentType, ctx)) {
                info = findResourceCompressed(libraryName, resourceName, isViewResource, localePrefix, contracts, ctx);
            } else {
               info = findResourceNonCompressed(libraryName, resourceName, isViewResource, localePrefix, contracts, ctx);
            }
        }

        return info;
    }

    public Stream<String> getViewResources(FacesContext facesContext, String path, int maxDepth, ResourceVisitOption... options) {
        return faceletWebappResourceHelper.getViewResources(facesContext, path, maxDepth, options);
    }

    // ----------------------------------------------------- Private Methods

    private ResourceInfo findResourceCompressed(String libraryName, String resourceName, boolean isViewResource, String localePrefix, List<String> contracts, FacesContext ctx) {

        ResourceInfo info = null;

        lock.lock();
        try {
            info = getFromCache(resourceName, libraryName, localePrefix, contracts);
            if (info == null) {
                info = doLookup(libraryName, resourceName, localePrefix, true, isViewResource, contracts, ctx);
                if (info != null) {
                    addToCache(info, contracts);
                }
            }
        } finally {
            lock.unlock();
        }

        return info;
    }

    private ResourceInfo findResourceNonCompressed(String libraryName, String resourceName, boolean isViewResource, String localePrefix, List<String> contracts, FacesContext ctx) {
        ResourceInfo info = doLookup(libraryName, resourceName, localePrefix, false, isViewResource, contracts, ctx);

        if (info == null && contracts != null) {
            info = doLookup(libraryNameFromContracts(libraryName, contracts), resourceName, localePrefix, false, isViewResource, contracts, ctx);
        }

        if (info != null && !info.isDoNotCache()) {
            addToCache(info, contracts);
        }

        return info;
    }

    private String libraryNameFromContracts(String libraryName, List<String> contracts) {
        // If the library name is equal to one of the contracts,
        // assume the resource to be found is within that contract
        for (String contract : contracts) {
            if (contract.equals(libraryName)) {
                return null;
            }
        }

        return libraryName;
    }

    /**
     * Attempt to look up the Resource based on the provided details.
     *
     * @param libraryName the name of the library (if any)
     * @param resourceName the name of the resource
     * @param localePrefix the locale prefix for this resource (if any)
     * @param compressable if this resource can be compressed
     * @param isViewResource
     * @param contracts the contracts to consider
     * @param ctx the {@link javax.faces.context.FacesContext} for the current
     *  request
     *
     * @return a {@link ResourceInfo} if a resource if found matching the
     *  provided arguments, otherwise, return <code>null</code>
     */
    private ResourceInfo doLookup(String libraryName, String resourceName, String localePrefix, boolean compressable, boolean isViewResource, List<String> contracts, FacesContext ctx) {

        // Loop over the contracts as described in deriveResourceIdConsideringLocalePrefixAndContracts in the spec
        for (String contract : contracts) {
            ResourceInfo info = getResourceInfo(libraryName, resourceName, localePrefix, contract, compressable, isViewResource, ctx, null);
            if (info != null) {
                return info;
            }
        }

        return getResourceInfo(libraryName, resourceName, localePrefix, null, compressable, isViewResource, ctx, null);
    }

    private ResourceInfo getResourceInfo(String libraryName, String resourceName, String localePrefix, String contract, boolean compressable, boolean isViewResource, FacesContext ctx, LibraryInfo library) {
        if (libraryName != null && !nameContainsForbiddenSequence(libraryName)) {
            library = findLibrary(libraryName, localePrefix, contract, ctx);

            if (library == null && localePrefix != null) {
                // no localized library found.  Try to find a library that isn't localized.
                library = findLibrary(libraryName, null, contract, ctx);
            }

            if (library == null) {
                // If we don't have one by now, perhaps it's time to consider scanning directories.
                library = findLibraryOnClasspathWithZipDirectoryEntryScan(libraryName, localePrefix, contract, ctx, false);

                if (library == null && localePrefix != null) {
                    // no localized library found.  Try to find
                    // a library that isn't localized.
                    library = findLibraryOnClasspathWithZipDirectoryEntryScan(libraryName, null, contract, ctx, false);
                }

                if (library == null) {
                    return null;
                }
            }
        } else if (nameContainsForbiddenSequence(libraryName)) {
            return null;
        }

        String resName = trimLeadingSlash(resourceName);
        if (nameContainsForbiddenSequence(resName) || (!isViewResource && resName.startsWith("WEB-INF"))) {
            return null;
        }

        ResourceInfo info = findResource(library, resourceName, localePrefix, compressable, isViewResource, ctx);
        if (info == null && localePrefix != null) {
            // no localized resource found, try to find a
            // resource that isn't localized
            info = findResource(library, resourceName, null, compressable, isViewResource, ctx);
        }

        // If no resource has been found so far, and we have a library that
        // was found in the webapp filesystem, see if there is a matching
        // library on the classpath.  If one is found, try to find a matching
        // resource in that library.
        if (info == null && library != null && library.getHelper() instanceof WebappResourceHelper) {
            LibraryInfo altLibrary = classpathResourceHelper.findLibrary(libraryName, localePrefix, contract, ctx);
            if (altLibrary != null) {
                VersionInfo originalVersion = library.getVersion();
                VersionInfo altVersion = altLibrary.getVersion();
                if (originalVersion == null && altVersion == null) {
                    library = altLibrary;
                } else if (originalVersion == null && altVersion != null) {
                    library = null;
                } else if (originalVersion != null && altVersion == null) {
                    library = null;
                } else if (originalVersion.compareTo(altVersion) == 0) {
                    library = altLibrary;
                }

            }

            if (library != null) {
                info = findResource(library, resourceName, localePrefix, compressable, isViewResource, ctx);
                if (info == null && localePrefix != null) {
                    // no localized resource found, try to find a
                    // resource that isn't localized
                    info = findResource(library, resourceName, null, compressable, isViewResource, ctx);
                }
            }
        }

        return info;
    }

    /**
     * @param s input String
     * @return the String without a leading slash if it has one.
     */
    private String trimLeadingSlash(String s) {
        if (s.charAt(0) == '/') {
            return s.substring(1);
        } else {
            return s;
        }
    }

    private static boolean nameContainsForbiddenSequence(String name) {
        boolean result = false;
        if (name != null) {
            name = name.toLowerCase();

            result = name.startsWith(".") ||
                     name.contains("../") ||
                     name.contains("..\\") ||
                     name.startsWith("/") ||
                     name.startsWith("\\") ||
                     name.endsWith("/") ||

                     name.contains("..%2f") ||
                     name.contains("..%5c") ||
                     name.startsWith("%2f") ||
                     name.startsWith("%5c") ||
                     name.endsWith("%2f") ||

                     name.contains("..\\u002f") ||
                     name.contains("..\\u005c") ||
                     name.startsWith("\\u002f") ||
                     name.startsWith("\\u005c") ||
                     name.endsWith("\\u002f")

                    ;
        }

        return result;
    }

    /**
     *
     * @param name the resource name
     * @param library the library name
     * @param localePrefix the Locale prefix
     * @param contracts
     * @return the {@link ResourceInfo} from the cache or <code>null</code>
     *  if no cached entry is found
     */
    private ResourceInfo getFromCache(String name, String library, String localePrefix, List<String> contracts) {
        if (cache == null) {
            return null;
        }

        return cache.get(name, library, localePrefix, contracts);
    }

    /**
     * Adds the the specified {@link ResourceInfo} to the cache.
     * @param info the @{link ResourceInfo} to add.
     * @param contracts the contracts
     */
    private void addToCache(ResourceInfo info, List<String> contracts) {
        if (cache == null) {
            return;
        }

        cache.add(info, contracts);
    }

    /**
     * <p> Attempt to lookup and return a {@link LibraryInfo} based on the
     * specified <code>arguments</code>.
     * <p/>
     * <p> The lookup process will first search the file system of the web
     * application *within the resources directory*.
     * If the library is not found, then it processed to
     * searching the classpath, if not found there, search from the webapp root
     * *excluding* the resources directory.</p>
     * <p/>
     * <p> If a library is found, this method will return a {@link
     * LibraryInfo} instance that contains the name, version, and {@link
     * ResourceHelper}.</p>
     *
     *
     * @param libraryName the library to find
     * @param localePrefix the prefix for the desired locale
     * @param contract the contract to use
     *@param ctx         the {@link javax.faces.context.FacesContext} for the current request
     *  @return the Library instance for the specified library
     */
     LibraryInfo findLibrary(String libraryName, String localePrefix, String contract, FacesContext ctx) {

        LibraryInfo library = webappResourceHelper.findLibrary(libraryName, localePrefix, contract, ctx);

        if (library == null) {
            library = classpathResourceHelper.findLibrary(libraryName, localePrefix, contract, ctx);
        }

        if (library == null && contract == null) {
            // FCAPUTO facelets in contracts should have been found by the webapphelper already
            library = faceletWebappResourceHelper.findLibrary(libraryName, localePrefix, contract, ctx);
        }

        // if not library is found at this point, let the caller deal with it
        return library;
    }

     LibraryInfo findLibraryOnClasspathWithZipDirectoryEntryScan(String libraryName,
                                                                 String localePrefix,
                                                                 String contract, FacesContext ctx, boolean forceScan) {
         return classpathResourceHelper.findLibraryWithZipDirectoryEntryScan(libraryName, localePrefix, contract, ctx, forceScan);
     }

   /**
     * <p> Attempt to lookup and return a {@link ResourceInfo} based on the
     * specified <code>arguments</code>.
     * <p/>
     * <p> The lookup process will first search the file system of the web
     * application.  If the library is not found, then it processed to
     * searching the classpath.</p>
     * <p/>
     * <p> If a library is found, this method will return a {@link
     * LibraryInfo} instance that contains the name, version, and {@link
     * ResourceHelper}.</p>
     *
     * @param library the library the resource should be found in
     * @param resourceName the name of the resource
     * @param localePrefix the prefix for the desired locale
     * @param compressable <code>true</code> if the resource can be compressed
     * @param ctx the {@link javax.faces.context.FacesContext} for the current request
     *
     * @return the Library instance for the specified library
     */
    private ResourceInfo findResource(LibraryInfo library,
                                      String resourceName,
                                      String localePrefix,
                                      boolean compressable,
                                      boolean skipToFaceletResourceHelper,
                                      FacesContext ctx) {

        if (library != null) {
            return library.getHelper().findResource(library,
                                                    resourceName,
                                                    localePrefix,
                                                    compressable,
                                                    ctx);
        } else {
            ResourceInfo resource = null;

            if (!skipToFaceletResourceHelper) {
                resource = webappResourceHelper.findResource(null,
                        resourceName,
                        localePrefix,
                        compressable,
                        ctx);
            }
            if (resource == null && !skipToFaceletResourceHelper) {
                resource = classpathResourceHelper.findResource(null,
                                                        resourceName,
                                                        localePrefix,
                                                        compressable,
                                                        ctx);
            }
            if (resource == null) {
                resource = faceletWebappResourceHelper.findResource(library,
                    resourceName,
                    localePrefix,
                    compressable,
                    ctx);
            }
            return resource;
        }

    }

    ResourceInfo findResource(String resourceId) {
        // PENDING(fcaputo) do we need to handle contracts here?
        String libraryName = null;
        String resourceName = null;
        int end = 0, start = 0;
        if (-1 != (end = resourceId.lastIndexOf("/"))) {
            resourceName = resourceId.substring(end+1);
            if (-1 != (start = resourceId.lastIndexOf("/", end - 1))) {
                libraryName = resourceId.substring(start+1, end);
            } else {
                libraryName = resourceId.substring(0, end);
            }
        }
        FacesContext context = FacesContext.getCurrentInstance();
        LibraryInfo info = this.findLibrary(libraryName, null, null, context);
        ResourceInfo resourceInfo = this.findResource(info, resourceName, libraryName, true, false, context);

        return resourceInfo;
    }

    /**
     * <p>
     * Obtains the application configured message resources for the current
     * request locale.  If a ResourceBundle is found and contains the key
     * <code>javax.faces.resource.localePrefix</code>, use the value associated
     * with that key as the prefix for locale specific resources.
     * </p>
     *
     * <p>
     * For example, say the request locale is en_US, and
     * <code>javax.faces.resourceLocalePrefix</code> is found with a value of
     * <code>en</code>, a resource path within a web application might look like
     * <code>/resources/en/corp/images/greetings.jpg</code>
     * </p>
     *
     * @param context the {@link FacesContext} for the current request
     * @return the localePrefix based on the current request, or <code>null</code>
     *  if no prefix can be determined
     */
    private String getLocalePrefix(FacesContext context) {

        String localePrefix = null;

        localePrefix = context.getExternalContext().getRequestParameterMap().get("loc");

        if(localePrefix != null){
            return localePrefix;
        }

        String appBundleName = context.getApplication().getMessageBundle();
        if (null != appBundleName) {

            Locale locale = null;
            if (context.getViewRoot() != null) {
                locale = context.getViewRoot().getLocale();
            } else {
                locale = context.getApplication().getViewHandler().calculateLocale(context);
            }

                try {
                    ResourceBundle appBundle =
                          ResourceBundle.getBundle(appBundleName,
                                                   locale,
                                                   Util.getCurrentLoader(ResourceManager.class));
                    localePrefix =
                          appBundle
                                .getString(ResourceHandler.LOCALE_PREFIX);
                } catch (MissingResourceException mre) {
                    if (LOGGER.isLoggable(Level.FINEST)) {
                        LOGGER.log(Level.FINEST, "Ignoring missing resource", mre);
                    }
                }
        }
        return localePrefix;

    }

    private List<String> getResourceLibraryContracts(FacesContext context) {
        UIViewRoot viewRoot = context.getViewRoot();
        if(viewRoot == null) {

            if(context.getApplication().getResourceHandler().isResourceRequest(context)) {
                // it is a resource request. look at the parameter con=.

                String param = context.getExternalContext().getRequestParameterMap().get("con");
                if(!nameContainsForbiddenSequence(param) && param != null && param.trim().length() > 0) {
                    return Arrays.asList(param);
                }
            }
            // PENDING(edburns): calculate the contracts!
            return Collections.emptyList();
        }
        return context.getResourceLibraryContracts();
    }

    /**
     * @param contentType content-type in question
     * @param ctx the @{link FacesContext} for the current request
     * @return <code>true</code> if this resource can be compressed, otherwise
     *  <code>false</code>
     */
    private boolean isCompressable(String contentType, FacesContext ctx) {

        // No compression when developing.
        if (contentType == null || ctx.isProjectStage(ProjectStage.Development)) {
            return false;
        } else {
            if (compressableTypes != null && !compressableTypes.isEmpty()) {
                for (Pattern p : compressableTypes) {
                    boolean matches = p.matcher(contentType).matches();
                    if (matches) {
                        return true;
                    }
                }
            }
        }

        return false;

    }

    /**
     * Init <code>compressableTypes</code> from the configuration.
     */
    private void initCompressableTypes(Map<String, Object> appMap) {

        WebConfiguration config = WebConfiguration.getInstance();
        String value = config.getOptionValue(WebConfiguration.WebContextInitParameter.CompressableMimeTypes);
        if (value != null && value.length() > 0) {
            String[] values = Util.split(appMap, value, ",");
            if (values != null) {
                for (String s : values) {
                    String pattern = s.trim();
                    if (!isPatternValid(pattern)) {
                        continue;
                    }
                    if (pattern.endsWith("/*")) {
                        pattern = pattern.substring(0, pattern.indexOf("/*"));
                        pattern += "/[a-z0-9.-]*";
                    }
                    if (compressableTypes == null) {
                        compressableTypes = new ArrayList<>(values.length);
                    }
                    try {
                        compressableTypes.add(Pattern.compile(pattern));
                    } catch (PatternSyntaxException pse) {
                        if (LOGGER.isLoggable(Level.WARNING)) {
                            // PENDING i18n
                            LOGGER.log(Level.WARNING,
                                       "jsf.resource.mime.type.configration.invalid",
                                       new Object[] { pattern, pse.getPattern()});
                        }
                    }
                }
            }
        }

    }

    /**
     * @param input input mime-type pattern from the configuration
     * @return <code>true</code> if the input matches the expected pattern,
     *  otherwise <code>false</code>
     */
    private boolean isPatternValid(String input) {

        return (CONFIG_MIMETYPE_PATTERN.matcher(input).matches());

    }

}

Output:
【漏洞类型】路径遍历漏洞
【严重性】High
【漏洞摘要】此代码存在路径遍历漏洞，主要体现在`ResourceManager`类的`getLocalePrefix`方法中。通过读取请求参数`loc`并直接使用，攻击者可以提供包含 "../" 或 "..\\\" 的值来访问文件系统的上级目录。此外，`InstanceFactory`类的`createComponent`方法在创建组件时未对用户输入进行验证，可能导致潜在的安全问题。
【关键代码模式】
- `nameContainsForbiddenSequence`函数：用于检查字符串中是否包含非法字符序列。
- `getLocalePrefix`方法：读取请求参数`loc`并使用，未进行安全性验证。
- `createComponent`方法：使用用户输入的`componentType`和`componentClass`，未进行安全性验证。
【修复方法说明】在`ResourceManager`类的`getLocalePrefix`方法中添加了对`loc`参数的合法性验证。在`InstanceFactory`类的`createComponent`方法中，添加了对`componentType`和`componentClass`参数的非空验证。这些修复方法通过验证用户输入，防止了路径遍历和其他潜在的安全问题。


Instruction:
作为 Java 安全专家，检测此代码中的安全漏洞：
## 内容1
### 文件路径：
core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSUtil.java
### 代码内容：
package org.bouncycastle.pqc.crypto.xmss;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;

import org.bouncycastle.crypto.Digest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;

/**
 * Utils for XMSS implementation.
 */
public class XMSSUtil
{

    /**
     * Calculates the logarithm base 2 for a given Integer.
     *
     * @param n Number.
     * @return Logarithm to base 2 of {@code n}.
     */
    public static int log2(int n)
    {
        int log = 0;
        while ((n >>= 1) != 0)
        {
            log++;
        }
        return log;
    }

    /**
     * Convert int/long to n-byte array.
     *
     * @param value      int/long value.
     * @param sizeInByte Size of byte array in byte.
     * @return int/long as big-endian byte array of size {@code sizeInByte}.
     */
    public static byte[] toBytesBigEndian(long value, int sizeInByte)
    {
        byte[] out = new byte[sizeInByte];
        for (int i = (sizeInByte - 1); i >= 0; i--)
        {
            out[i] = (byte)value;
            value >>>= 8;
        }
        return out;
    }

    /*
     * Copy long to byte array in big-endian at specific offset.
     */
    public static void longToBigEndian(long value, byte[] in, int offset)
    {
        if (in == null)
        {
            throw new NullPointerException("in == null");
        }
        if ((in.length - offset) < 8)
        {
            throw new IllegalArgumentException("not enough space in array");
        }
        in[offset] = (byte)((value >> 56) & 0xff);
        in[offset + 1] = (byte)((value >> 48) & 0xff);
        in[offset + 2] = (byte)((value >> 40) & 0xff);
        in[offset + 3] = (byte)((value >> 32) & 0xff);
        in[offset + 4] = (byte)((value >> 24) & 0xff);
        in[offset + 5] = (byte)((value >> 16) & 0xff);
        in[offset + 6] = (byte)((value >> 8) & 0xff);
        in[offset + 7] = (byte)((value) & 0xff);
    }

    /*
     * Generic convert from big endian byte array to long.
     */
    public static long bytesToXBigEndian(byte[] in, int offset, int size)
    {
        if (in == null)
        {
            throw new NullPointerException("in == null");
        }
        long res = 0;
        for (int i = offset; i < (offset + size); i++)
        {
            res = (res << 8) | (in[i] & 0xff);
        }
        return res;
    }

    /**
     * Clone a byte array.
     *
     * @param in byte array.
     * @return Copy of byte array.
     */
    public static byte[] cloneArray(byte[] in)
    {
        if (in == null)
        {
            throw new NullPointerException("in == null");
        }
        byte[] out = new byte[in.length];
        for (int i = 0; i < in.length; i++)
        {
            out[i] = in[i];
        }
        return out;
    }

    /**
     * Clone a 2d byte array.
     *
     * @param in 2d byte array.
     * @return Copy of 2d byte array.
     */
    public static byte[][] cloneArray(byte[][] in)
    {
        if (hasNullPointer(in))
        {
            throw new NullPointerException("in has null pointers");
        }
        byte[][] out = new byte[in.length][];
        for (int i = 0; i < in.length; i++)
        {
            out[i] = new byte[in[i].length];
            for (int j = 0; j < in[i].length; j++)
            {
                out[i][j] = in[i][j];
            }
        }
        return out;
    }

    /**
     * Compares two 2d-byte arrays.
     *
     * @param a 2d-byte array 1.
     * @param b 2d-byte array 2.
     * @return true if all values in 2d-byte array are equal false else.
     */
    public static boolean areEqual(byte[][] a, byte[][] b)
    {
        if (hasNullPointer(a) || hasNullPointer(b))
        {
            throw new NullPointerException("a or b == null");
        }
        for (int i = 0; i < a.length; i++)
        {
            if (!Arrays.areEqual(a[i], b[i]))
            {
                return false;
            }
        }
        return true;
    }

    /**
     * Dump content of 2d byte array.
     *
     * @param x byte array.
     */
    public static void dumpByteArray(byte[][] x)
    {
        if (hasNullPointer(x))
        {
            throw new NullPointerException("x has null pointers");
        }
        for (int i = 0; i < x.length; i++)
        {
            System.out.println(Hex.toHexString(x[i]));
        }
    }

    /**
     * Checks whether 2d byte array has null pointers.
     *
     * @param in 2d byte array.
     * @return true if at least one null pointer is found false else.
     */
    public static boolean hasNullPointer(byte[][] in)
    {
        if (in == null)
        {
            return true;
        }
        for (int i = 0; i < in.length; i++)
        {
            if (in[i] == null)
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Copy src byte array to dst byte array at offset.
     *
     * @param dst    Destination.
     * @param src    Source.
     * @param offset Destination offset.
     */
    public static void copyBytesAtOffset(byte[] dst, byte[] src, int offset)
    {
        if (dst == null)
        {
            throw new NullPointerException("dst == null");
        }
        if (src == null)
        {
            throw new NullPointerException("src == null");
        }
        if (offset < 0)
        {
            throw new IllegalArgumentException("offset hast to be >= 0");
        }
        if ((src.length + offset) > dst.length)
        {
            throw new IllegalArgumentException("src length + offset must not be greater than size of destination");
        }
        for (int i = 0; i < src.length; i++)
        {
            dst[offset + i] = src[i];
        }
    }

    /**
     * Copy length bytes at position offset from src.
     *
     * @param src    Source byte array.
     * @param offset Offset in source byte array.
     * @param length Length of bytes to copy.
     * @return New byte array.
     */
    public static byte[] extractBytesAtOffset(byte[] src, int offset, int length)
    {
        if (src == null)
        {
            throw new NullPointerException("src == null");
        }
        if (offset < 0)
        {
            throw new IllegalArgumentException("offset hast to be >= 0");
        }
        if (length < 0)
        {
            throw new IllegalArgumentException("length hast to be >= 0");
        }
        if ((offset + length) > src.length)
        {
            throw new IllegalArgumentException("offset + length must not be greater then size of source array");
        }
        byte[] out = new byte[length];
        for (int i = 0; i < out.length; i++)
        {
            out[i] = src[offset + i];
        }
        return out;
    }

    /**
     * Check whether an index is valid or not.
     *
     * @param height Height of binary tree.
     * @param index  Index to validate.
     * @return true if index is valid false else.
     */
    public static boolean isIndexValid(int height, long index)
    {
        if (index < 0)
        {
            throw new IllegalStateException("index must not be negative");
        }
        return index < (1L << height);
    }

    /**
     * Determine digest size of digest.
     *
     * @param digest Digest.
     * @return Digest size.
     */
    public static int getDigestSize(Digest digest)
    {
        if (digest == null)
        {
            throw new NullPointerException("digest == null");
        }
        String algorithmName = digest.getAlgorithmName();
        if (algorithmName.equals("SHAKE128"))
        {
            return 32;
        }
        if (algorithmName.equals("SHAKE256"))
        {
            return 64;
        }
        return digest.getDigestSize();
    }

    public static long getTreeIndex(long index, int xmssTreeHeight)
    {
        return index >> xmssTreeHeight;
    }

    public static int getLeafIndex(long index, int xmssTreeHeight)
    {
        return (int)(index & ((1L << xmssTreeHeight) - 1L));
    }

    public static byte[] serialize(Object obj)
        throws IOException
    {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(out);
        oos.writeObject(obj);
        oos.flush();
        return out.toByteArray();
    }

    public static Object deserialize(byte[] data, final Class clazz)
        throws IOException, ClassNotFoundException
    {
        ByteArrayInputStream in = new ByteArrayInputStream(data);
        ObjectInputStream is = new CheckingStream(clazz, in);

        Object obj = is.readObject();

        if (is.available() != 0)
        {
            throw new IOException("unexpected data found at end of ObjectInputStream");
        }
        // you'd hope this would always succeed!
        if (clazz.isInstance(obj))
        {
            return obj;
        }
        else
        {
            throw new IOException("unexpected class found in ObjectInputStream");
        }
    }

    public static int calculateTau(int index, int height)
    {
        int tau = 0;
        for (int i = 0; i < height; i++)
        {
            if (((index >> i) & 1) == 0)
            {
                tau = i;
                break;
            }
        }
        return tau;
    }

    public static boolean isNewBDSInitNeeded(long globalIndex, int xmssHeight, int layer)
    {
        if (globalIndex == 0)
        {
            return false;
        }
        return (globalIndex % (long)Math.pow((1 << xmssHeight), layer + 1) == 0) ? true : false;
    }

    public static boolean isNewAuthenticationPathNeeded(long globalIndex, int xmssHeight, int layer)
    {
        if (globalIndex == 0)
        {
            return false;
        }
        return ((globalIndex + 1) % (long)Math.pow((1 << xmssHeight), layer) == 0) ? true : false;
    }

    private static class CheckingStream
       extends ObjectInputStream
    {
        private final Class mainClass;
        private boolean found = false;

        CheckingStream(Class mainClass, InputStream in)
            throws IOException
        {
            super(in);

            this.mainClass = mainClass;
        }

        protected Class<?> resolveClass(ObjectStreamClass desc)
            throws IOException,
            ClassNotFoundException
        {
            if (!found)
            {
                if (!desc.getName().equals(mainClass.getName()))
                {
                    throw new InvalidClassException(
                        "unexpected class: ", desc.getName());
                }
                else
                {
                    found = true;
                }
            }
            return super.resolveClass(desc);
        }
    }
}

Output:
【漏洞类型】反序列化漏洞
【严重性】High
【漏洞摘要】此代码存在反序列化漏洞。具体表现为`deserialize`方法中使用`ObjectInputStream`来反序列化传入的字节数组。尽管`CheckingStream`类尝试通过`resolveClass`方法限制反序列化的类，但该限制仅针对主类，而其他组件类仍然可以被反序列化。攻击者可以通过构造恶意的序列化数据来利用这个漏洞执行任意代码。
【关键代码模式】`ObjectInputStream`、`resolveClass`、`deserialize`、`CheckingStream`。
【修复方法说明】修复方法通过在`CheckingStream`类中添加一个静态的`components`集合，限制了可以反序列化的类列表。这样可以更全面地防止未授权的类被反序列化。