001/*
002 *   Copyright (C) Christian Schulte, 2011-293
003 *   All rights reserved.
004 *
005 *   Redistribution and use in source and binary forms, with or without
006 *   modification, are permitted provided that the following conditions
007 *   are met:
008 *
009 *     o Redistributions of source code must retain the above copyright
010 *       notice, this list of conditions and the following disclaimer.
011 *
012 *     o Redistributions in binary form must reproduce the above copyright
013 *       notice, this list of conditions and the following disclaimer in
014 *       the documentation and/or other materials provided with the
015 *       distribution.
016 *
017 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 *
028 *   $JOMC: KeyValueType.java 4613 2012-09-22 10:07:08Z schulte $
029 *
030 */
031package org.jomc.mojo;
032
033import java.lang.reflect.InvocationTargetException;
034import java.lang.reflect.Method;
035import java.lang.reflect.Modifier;
036import org.apache.commons.lang.builder.ToStringBuilder;
037
038/**
039 * Datatype holding a {@code key}, {@code value} and {@code type} property.
040 *
041 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
042 * @version $JOMC: KeyValueType.java 4613 2012-09-22 10:07:08Z schulte $
043 * @since 1.2
044 */
045public class KeyValueType implements Cloneable
046{
047
048    /** The key of the type. */
049    private String key;
050
051    /** The value of the type. */
052    private String value;
053
054    /** The name of the class of the type of {@code value}. */
055    private String type;
056
057    /** Creates a new {@code KeyValueType} instance. */
058    public KeyValueType()
059    {
060        super();
061    }
062
063    /**
064     * Gets the value of the {@code key} property.
065     *
066     * @return The value of the {@code key} property.
067     *
068     * @see #setKey(java.lang.String)
069     */
070    public final String getKey()
071    {
072        return this.key;
073    }
074
075    /**
076     * Sets the value of the {@code key} property.
077     *
078     * @param k The new value of the {@code key} property.
079     *
080     * @see #getKey()
081     */
082    public final void setKey( final String k )
083    {
084        this.key = k;
085    }
086
087    /**
088     * Gets the value of the {@code value} property.
089     *
090     * @return The value of the {@code value} property or {@code null}.
091     *
092     * @see #setValue(java.lang.String)
093     */
094    public final String getValue()
095    {
096        return this.value;
097    }
098
099    /**
100     * Sets the value of the {@code value} property.
101     *
102     * @param v The new value of the {@code value} property or {@code null}.
103     *
104     * @see #getValue()
105     */
106    public final void setValue( final String v )
107    {
108        this.value = v;
109    }
110
111    /**
112     * Gets the value of the {@code type} property.
113     *
114     * @return The value of the {@code type} property or {@code null}.
115     *
116     * @see #setType(java.lang.String)
117     */
118    public final String getType()
119    {
120        return this.type;
121    }
122
123    /**
124     * Sets the value of the {@code type} property.
125     *
126     * @param t The new value of the {@code type} property or {@code null}.
127     *
128     * @see #getType()
129     */
130    public final void setType( final String t )
131    {
132        this.type = t;
133    }
134
135    /**
136     * Gets the object of the instance.
137     *
138     * @return The object of the instance or {@code null}.
139     *
140     * @throws InstantiationException if getting the object of the instance fails.
141     *
142     * @see #getType()
143     * @see #getValue()
144     */
145    public Object getObject() throws InstantiationException // JDK: As of JDK 7, "throws ReflectiveOperationException".
146    {
147        Class<?> javaClass = null;
148        Object o = this.getValue();
149
150        try
151        {
152            if ( o != null )
153            {
154                if ( this.getType() != null && !String.class.getName().equals( this.getType() ) )
155                {
156                    javaClass = Class.forName( this.getType() );
157
158                    try
159                    {
160                        o = javaClass.getConstructor( String.class ).newInstance( o );
161                    }
162                    catch ( final NoSuchMethodException e )
163                    {
164                        final Method valueOf = javaClass.getMethod( "valueOf", String.class );
165
166                        if ( Modifier.isStatic( valueOf.getModifiers() )
167                             && valueOf.getReturnType().equals( javaClass ) )
168                        {
169                            o = valueOf.invoke( null, o );
170                        }
171                        else
172                        {
173                            throw (InstantiationException) new InstantiationException(
174                                Messages.getMessage( "noSuchMethodCreatingObject", this.getType(), this.getValue(),
175                                                     javaClass.getSimpleName() ) ).initCause( e );
176
177                        }
178                    }
179                }
180            }
181            else if ( this.getType() != null )
182            {
183                o = Class.forName( this.getType() ).newInstance();
184            }
185
186            return o;
187        }
188        catch ( final ClassNotFoundException e )
189        {
190            throw (InstantiationException) new InstantiationException(
191                Messages.getMessage( "failedCreatingObject", this.getType() ) ).initCause( e );
192
193        }
194        catch ( final NoSuchMethodException e )
195        {
196            throw (InstantiationException) new InstantiationException(
197                Messages.getMessage( "noSuchMethodCreatingObject", this.getType(), this.getValue(),
198                                     javaClass.getSimpleName() ) ).initCause( e );
199
200        }
201        catch ( final IllegalAccessException e )
202        {
203            throw (InstantiationException) new InstantiationException(
204                Messages.getMessage( "failedCreatingObject", this.getType() ) ).initCause( e );
205
206        }
207        catch ( final InvocationTargetException e )
208        {
209            throw (InstantiationException) new InstantiationException(
210                Messages.getMessage( "failedCreatingObject", this.getType() ) ).initCause( e );
211
212        }
213    }
214
215    /**
216     * Creates and returns a copy of this object.
217     *
218     * @return A copy of this object.
219     */
220    @Override
221    public KeyValueType clone()
222    {
223        try
224        {
225            return (KeyValueType) super.clone();
226        }
227        catch ( final CloneNotSupportedException e )
228        {
229            throw new AssertionError( e );
230        }
231    }
232
233    /**
234     * Creates and returns a string representation of the object.
235     *
236     * @return A string representation of the object.
237     */
238    @Override
239    public String toString()
240    {
241        return ToStringBuilder.reflectionToString( this );
242    }
243
244}