ConstructorArg.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.configuration2.beanutils;

  18. import java.util.Objects;

  19. /**
  20.  * <p>
  21.  * A class representing an argument for a constructor invocation to be used by a {@link BeanDeclaration}.
  22.  * </p>
  23.  * <p>
  24.  * A {@code BeanDeclaration} can provide a list of instances of this class to define the constructor to be invoked on
  25.  * the bean class. Each constructor argument can either be a simple value or a nested {@code BeanDeclaration}. In the
  26.  * latter case, the bean is resolved recursively.
  27.  * </p>
  28.  * <p>
  29.  * The constructor to be invoked on the bean class has to be determined based on the types of the constructor arguments.
  30.  * To avoid ambiguity, the type name can be explicitly provided.
  31.  * </p>
  32.  *
  33.  * @since 2.0
  34.  */
  35. public final class ConstructorArg {

  36.     /**
  37.      * Creates a new instance of {@code ConstructorArg} for the specified {@code BeanDeclaration}. The actual value of this
  38.      * argument is the resolved {@code BeanDeclaration}.
  39.      *
  40.      * @param decl the {@code BeanDeclaration}
  41.      * @return the newly created instance of this class
  42.      * @throws NullPointerException if the {@code BeanDeclaration} is <strong>null</strong>
  43.      */
  44.     public static ConstructorArg forBeanDeclaration(final BeanDeclaration decl) {
  45.         return forBeanDeclaration(decl, null);
  46.     }

  47.     /**
  48.      * Creates a new instance of {@code ConstructorArg} for the specified {@code BeanDeclaration} and sets the type name
  49.      * explicitly. The type name is used to match this argument against the parameter type of a constructor or the bean
  50.      * class.
  51.      *
  52.      * @param beanDeclaration the {@code BeanDeclaration}
  53.      * @param typeName the name of the data type of this argument
  54.      * @return the newly created instance of this class
  55.      * @throws NullPointerException if the {@code BeanDeclaration} is <strong>null</strong>
  56.      */
  57.     public static ConstructorArg forBeanDeclaration(final BeanDeclaration beanDeclaration, final String typeName) {
  58.         Objects.requireNonNull(beanDeclaration, "beanDeclaration");
  59.         return new ConstructorArg(beanDeclaration, null, typeName);
  60.     }

  61.     /**
  62.      * Creates a new instance of {@code ConstructorArg} for the specified simple value. The value is passed to the
  63.      * constructor invocation.
  64.      *
  65.      * @param value the value of this constructor argument (may be <strong>null</strong>)
  66.      * @return the newly created instance of this class
  67.      */
  68.     public static ConstructorArg forValue(final Object value) {
  69.         return forValue(value, null);
  70.     }

  71.     /**
  72.      * Creates a new instance of {@code ConstructorArg} for the specified simple value and sets the type name explicitly.
  73.      * The type name is used to match this argument against the parameter type of a constructor or the bean class.
  74.      *
  75.      * @param value the value of this constructor argument (may be <strong>null</strong>)
  76.      * @param typeName the name of the data type of this argument
  77.      * @return the newly created instance of this class
  78.      */
  79.     public static ConstructorArg forValue(final Object value, final String typeName) {
  80.         return new ConstructorArg(null, value, typeName);
  81.     }

  82.     /** The bean declaration referenced by this constructor argument. */
  83.     private final BeanDeclaration beanDeclaration;

  84.     /** The value of this constructor argument. */
  85.     private final Object value;

  86.     /** The name of the argument type. */
  87.     private final String typeName;

  88.     /**
  89.      * Constructs a new instance of {@code ConstructorArg}.
  90.      *
  91.      * @param decl the associated bean declaration
  92.      * @param val the value of the argument
  93.      * @param type the type name
  94.      */
  95.     private ConstructorArg(final BeanDeclaration decl, final Object val, final String type) {
  96.         beanDeclaration = decl;
  97.         value = val;
  98.         typeName = type;
  99.     }

  100.     /**
  101.      * Gets the {@code BeanDeclaration} referenced by this constructor argument. A return value of <strong>null</strong> means that
  102.      * this constructor argument does not have a bean declaration as value; in this case, the value can be queried using the
  103.      * {@link #getValue()} method.
  104.      *
  105.      * @return the referenced {@code BeanDeclaration} or <strong>null</strong>
  106.      */
  107.     public BeanDeclaration getBeanDeclaration() {
  108.         return beanDeclaration;
  109.     }

  110.     /**
  111.      * Gets the optional data type name of this constructor argument. The type name can be specified as a hint to select
  112.      * a specific constructor if there are ambiguities. Note that it does not necessarily has to match the data type of this
  113.      * argument's value because a type conversion may be performed before invoking the constructor.
  114.      *
  115.      * @return the data type name of this argument if defined or <strong>null</strong> otherwise
  116.      */
  117.     public String getTypeName() {
  118.         return typeName;
  119.     }

  120.     /**
  121.      * Gets the value of this constructor argument. This method can be queried if {@link #isNestedBeanDeclaration()}
  122.      * returns <strong>false</strong>. Note that a return value of <strong>null</strong> is legal (to pass <strong>null</strong> to a constructor
  123.      * argument).
  124.      *
  125.      * @return the simple value of this constructor argument
  126.      */
  127.     public Object getValue() {
  128.         return value;
  129.     }

  130.     /**
  131.      * Tests whether this constructor argument represents a {@code BeanDeclaration}. If this method returns
  132.      * <strong>true</strong>, the actual value of this argument can be obtained by resolving the bean declaration returned by
  133.      * {@link #getBeanDeclaration()}. Otherwise, this argument has a simple value which can be queried using
  134.      * {@link #getValue()}.
  135.      *
  136.      * @return whether this constructor argument references a bean declaration
  137.      */
  138.     public boolean isNestedBeanDeclaration() {
  139.         return getBeanDeclaration() != null;
  140.     }

  141.     /**
  142.      * Checks whether this constructor argument is compatible with the given class. This method is called to determine a
  143.      * matching constructor. It compares the argument's data type with the class name if it is defined. If no type name has
  144.      * been set, result is <strong>true</strong> as it is assumed that a type conversion can be performed when calling the
  145.      * constructor. This means that per default only the number of constructor arguments is checked to find a matching
  146.      * constructor. Only if there are multiple constructors with the same number of arguments, explicit type names have to
  147.      * be provided to select a specific constructor.
  148.      *
  149.      * @param argCls the class of the constructor argument to compare with
  150.      * @return <strong>true</strong> if this constructor argument is compatible with this class, <strong>false</strong> otherwise
  151.      */
  152.     public boolean matches(final Class<?> argCls) {
  153.         if (argCls == null) {
  154.             return false;
  155.         }

  156.         return getTypeName() == null || getTypeName().equals(argCls.getName());
  157.     }

  158.     /**
  159.      * Gets a string representation of this object. This string contains the value of this constructor argument and the
  160.      * explicit type if provided.
  161.      *
  162.      * @return a string for this object
  163.      */
  164.     @Override
  165.     public String toString() {
  166.         final StringBuilder buf = new StringBuilder();
  167.         buf.append(getClass().getSimpleName());
  168.         buf.append(" [ value = ");
  169.         buf.append(isNestedBeanDeclaration() ? getBeanDeclaration() : getValue());
  170.         if (getTypeName() != null) {
  171.             buf.append(" (").append(getTypeName()).append(')');
  172.         }
  173.         buf.append(" ]");
  174.         return buf.toString();
  175.     }
  176. }