001package org.apache.commons.beanutils2;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import static org.apache.commons.beanutils2.Assertions.checkArgument;
023import static org.apache.commons.beanutils2.Assertions.checkNotNull;
024import static org.apache.commons.beanutils2.TypeUtils.isAssignmentCompatible;
025
026/**
027 * An argument represents a value of some type that can be passed to a method or
028 * constructor.
029 *
030 * @param <T> the type of the argument.
031 */
032public final class Argument<T>
033{
034
035    /**
036     * Factory method for arguments. Creates an argument by taking a value and determining the type of the given value.
037     *
038     * @param value the value to be wrapped by the new argument object. Must not be {@code null}! If you want to create
039     *            a null argument use {@link #nullArgument(Class)} instead.
040     * @param <A> the type of the argument.
041     * @return a new argument of type {@code value.getClass()}
042     */
043    public static <A> Argument<A> argument( A value )
044    {
045        value = checkNotNull( value, "Null not supported when specifying value only" );
046        @SuppressWarnings( "unchecked" )
047        Class<A> type = (Class<A>) value.getClass();
048        return argument( type, value );
049    }
050
051    /**
052     * Creates a new null argument of the given type. Shortcut for {@code argument( type, null )}.
053     *
054     * @param type the type of the new argument. Must not be {@code null}!
055     * @param <A> the type of argument.
056     * @return an argument with {@code value == null}.
057     */
058    public static <A> Argument<A> nullArgument( Class<A> type )
059    {
060        return argument( type, null );
061    }
062
063    /**
064     * Creates a new argument of the given type with the given value.
065     *
066     * @param type the type of the new argument. Must not be {@code null}!
067     * @param value the value of the new argument.
068     * @param <T> the type of the argument.
069     * @param <V> the type of the value of the argument.
070     * @return a new argument of the given type with the given value.
071     */
072    public static <T, V extends T> Argument<T> argument( Class<T> type, V value )
073    {
074        type = checkNotNull( type, "type must be specified (while value is nullable)" );
075        if ( value != null )
076        {
077            // this should never happen since the compiler prevents it. Check it anyway...
078            checkArgument( isAssignmentCompatible( type, value.getClass() ),
079                           "value type %s does not match the given type %s",
080                           value.getClass().getName(),
081                           type.getName() );
082        }
083        return new Argument<T>( type, value );
084    }
085
086    /**
087     * Determines the types of the given arguments.
088     *
089     * @param arguments the arguments to determine the types of. None must be {@code null}!
090     * @return an array of {@code Class} objects representing the types of the
091     *         given arguments. The first {@code class} object represents the
092     *         type of the first argument and so on.
093     */
094    static Class<?>[] getParameterTypes( Argument<?>...arguments )
095    {
096        int argumentsLength = arguments.length;
097        Class<?>[] parameterTypes = new Class[argumentsLength];
098        for ( int i = 0; i < argumentsLength; i++ )
099        {
100            parameterTypes[i] = arguments[i].getType();
101        }
102        return parameterTypes;
103    }
104
105    /**
106     * Determines the objects of the given arguments.
107     *
108     * @param arguments the arguments to determine the types of. None must be {@code null}!
109     * @return an array of {@code Object}s representing the values of the given arguments.
110     */
111    static Object[] getParameters( Argument<?>...arguments )
112    {
113        int argumentsLength = arguments.length;
114        Object[] parameters = new Object[argumentsLength];
115        for ( int i = 0; i < argumentsLength; i++ )
116        {
117            parameters[i] = arguments[i].getValue();
118        }
119        return parameters;
120    }
121
122    private final Class<T> type;
123
124    private final T value;
125
126    private Argument( Class<T> type, T value )
127    {
128        this.type = type;
129        this.value = value;
130    }
131
132    /**
133     * Returns the argument's type. Note that the type returned maybe a super type of the actual type of the value
134     * returned by {@link #getValue()} depending on how the argument was created. For example:
135     * </br>{@code argument( Number.class, Integer.valueOf( 4 ) );}</br>
136     * will create an argument with an Integer as Value but Number.class as type.
137     *
138     * @return the argument's type
139     */
140    public Class<T> getType()
141    {
142        return type;
143    }
144
145    /**
146     * Returns the value of the argument. Maybe {@code null} if this is a null argument.
147     *
148     * @return the value of the argument.
149     */
150    public T getValue()
151    {
152        return value;
153    }
154
155}