001    /*****************************************************************************
002     * Copyright (c) PicoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     * Idea by Rachel Davies, Original code by Jon Tirsen                        *
009     *****************************************************************************/
010    
011    package org.picocontainer.parameters;
012    
013    import org.picocontainer.ComponentAdapter;
014    import org.picocontainer.Parameter;
015    import org.picocontainer.PicoContainer;
016    import org.picocontainer.PicoException;
017    import org.picocontainer.PicoCompositionException;
018    import org.picocontainer.PicoVisitor;
019    import org.picocontainer.NameBinding;
020    
021    import java.io.Serializable;
022    import java.lang.reflect.Field;
023    import java.lang.reflect.ParameterizedType;
024    import java.lang.reflect.Type;
025    import java.lang.annotation.Annotation;
026    
027    
028    /**
029     * A ConstantParameter should be used to pass in "constant" arguments to constructors. This
030     * includes {@link String}s,{@link Integer}s or any other object that is not registered in
031     * the container.
032     *
033     * @author Jon Tirsén
034     * @author Aslak Hellesøy
035     * @author Jörg Schaible
036     * @author Thomas Heller
037     */
038    @SuppressWarnings("serial")
039    public class ConstantParameter extends AbstractParameter implements Parameter, Serializable {
040    
041        private final Object value;
042        
043    
044        public ConstantParameter(Object value) {
045            this.value = value;
046        }
047    
048        public Resolver resolve(PicoContainer container, ComponentAdapter<?> forAdapter,
049                                ComponentAdapter<?> injecteeAdapter, final Type expectedType, NameBinding expectedNameBinding,
050                                boolean useNames, Annotation binding) {
051            if (expectedType instanceof Class) {
052                return new Parameter.ValueResolver(isAssignable((Class) expectedType), value, null);
053            } else if (expectedType instanceof ParameterizedType) {
054                    return new Parameter.ValueResolver(isAssignable(((ParameterizedType)expectedType).getRawType()), value, null);
055            }
056            return new Parameter.ValueResolver(true, value, null);
057        }
058    
059        /**
060         * {@inheritDoc}
061         *
062         * @see Parameter#verify(org.picocontainer.PicoContainer,org.picocontainer.ComponentAdapter,java.lang.reflect.Type,org.picocontainer.NameBinding,boolean,java.lang.annotation.Annotation)
063         */
064        public void verify(PicoContainer container, ComponentAdapter<?> adapter,
065                           Type expectedType, NameBinding expectedNameBinding,
066                           boolean useNames, Annotation binding) throws PicoException {
067            if (!isAssignable(expectedType)) {
068                throw new PicoCompositionException(
069                    expectedType + " is not assignable from " +
070                            (value != null ? value.getClass().getName() : "null"));
071            }
072        }
073    
074        protected boolean isAssignable(Type expectedType) {
075            boolean isAssignable;
076            if (expectedType instanceof Class) {
077                Class expectedClass = (Class) expectedType;
078                if (checkPrimitive(expectedClass) || expectedClass.isInstance(value)) {
079                    return true;
080                }
081            }
082            return false;
083        }
084    
085        /**
086         * Visit the current {@link Parameter}.
087         *
088         * @see org.picocontainer.Parameter#accept(org.picocontainer.PicoVisitor)
089         */
090        public void accept(final PicoVisitor visitor) {
091            visitor.visitParameter(this);
092        }
093    
094        private boolean checkPrimitive(Class expectedType) {
095            try {
096                if (expectedType.isPrimitive()) {
097                    final Field field = value.getClass().getField("TYPE");
098                    final Class type = (Class) field.get(value);
099                    return expectedType.isAssignableFrom(type);
100                }
101            } catch (NoSuchFieldException e) {
102                //ignore
103            } catch (IllegalAccessException e) {
104                //ignore
105            }
106            return false;
107        }
108    
109    }