001 package org.apache.commons.digester3.binder;
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
022 import static java.lang.String.format;
023
024 import java.util.Arrays;
025
026 import org.apache.commons.digester3.ObjectCreateRule;
027
028 /**
029 * Builder chained when invoking {@link LinkedRuleBuilder#createObject()}.
030 *
031 * @since 3.0
032 */
033 public final class ObjectCreateBuilder
034 extends AbstractBackToLinkedRuleBuilder<ObjectCreateRule>
035 {
036
037 private final ClassLoader classLoader;
038
039 private Class<?> type;
040
041 private String attributeName;
042
043 /**
044 * The constructor argument types
045 *
046 * @since 3.2
047 */
048 private Class<?>[] constructorArgumentsType;
049
050 /**
051 * Default constructor arguments.
052 *
053 * @since 3.2
054 */
055 private Object[] defaultConstructorArguments;
056
057 ObjectCreateBuilder( String keyPattern, String namespaceURI, RulesBinder mainBinder, LinkedRuleBuilder mainBuilder,
058 ClassLoader classLoader )
059 {
060 super( keyPattern, namespaceURI, mainBinder, mainBuilder );
061 this.classLoader = classLoader;
062 }
063
064 /**
065 * Construct an object with the specified class name.
066 *
067 * @param className Java class name of the object to be created
068 * @return this builder instance
069 */
070 public ObjectCreateBuilder ofType( String className )
071 {
072 if ( className == null )
073 {
074 reportError( "createObject().ofType( String )", "NULL Java type not allowed" );
075 return this;
076 }
077
078 try
079 {
080 return ofType( this.classLoader.loadClass( className ) );
081 }
082 catch ( ClassNotFoundException e )
083 {
084 reportError( "createObject().ofType( String )", String.format( "class '%s' cannot be load", className ) );
085 return this;
086 }
087 }
088
089 /**
090 * Construct an object with the specified class.
091 *
092 * @param <T> any java type
093 * @param type Java class of the object to be created
094 * @return this builder instance
095 */
096 public <T> ObjectCreateBuilder ofType( Class<T> type )
097 {
098 if ( type == null )
099 {
100 reportError( "createObject().ofType( Class<?> )", "NULL Java type not allowed" );
101 return this;
102 }
103
104 this.type = type;
105
106 return this;
107 }
108
109 /**
110 * Allows specify the attribute containing an override class name if it is present.
111 *
112 * @param attributeName The attribute containing an override class name if it is present
113 * @return this builder instance
114 */
115 public ObjectCreateBuilder ofTypeSpecifiedByAttribute( /* @Nullable */String attributeName )
116 {
117 this.attributeName = attributeName;
118 return this;
119 }
120
121 /**
122 * Allows users to specify constructor argument type names.
123 *
124 * @param paramTypeNames the constructor argument type names
125 * @return this builder instance
126 * @since 3.2
127 */
128 public ObjectCreateBuilder usingConstructor( String...paramTypeNames )
129 {
130 if ( paramTypeNames == null )
131 {
132 reportError( "createObject().usingConstructor( String[] )", "NULL parametersTypes not allowed" );
133 return this;
134 }
135
136 Class<?>[] paramTypes = new Class<?>[paramTypeNames.length];
137 for ( int i = 0; i < paramTypeNames.length; i++ )
138 {
139 try
140 {
141 paramTypes[i] = classLoader.loadClass( paramTypeNames[i] );
142 }
143 catch ( ClassNotFoundException e )
144 {
145 this.reportError( format( "createObject().usingConstructor( %s )",
146 Arrays.toString( paramTypeNames ) ),
147 format( "class '%s' cannot be loaded", paramTypeNames[i] ) );
148 }
149 }
150
151 return usingConstructor( paramTypes );
152 }
153
154 /**
155 * Allows users to specify constructor argument types.
156 *
157 * @param constructorArgumentTypes the constructor argument types
158 * @return this builder instance
159 * @since 3.2
160 */
161 public ObjectCreateBuilder usingConstructor( Class<?>... constructorArgumentTypes )
162 {
163 if ( constructorArgumentTypes == null )
164 {
165 reportError( "createObject().usingConstructor( Class<?>[] )",
166 "NULL constructorArgumentTypes not allowed" );
167 return this;
168 }
169
170 this.constructorArgumentsType = constructorArgumentTypes;
171
172 return this;
173 }
174
175 /**
176 * Allows users to specify default constructor arguments.
177 *
178 * @param defaultConstructorArguments the default constructor arguments.
179 * @return this builder instance
180 * @since 3.2
181 */
182 public ObjectCreateBuilder usingDefaultConstructorArguments( Object... defaultConstructorArguments )
183 {
184 if ( defaultConstructorArguments == null )
185 {
186 reportError( "createObject().usingDefaultConstructorArguments( Object[] )",
187 "NULL defaultConstructorArguments not allowed" );
188 return this;
189 }
190
191 this.defaultConstructorArguments = defaultConstructorArguments;
192
193 return this;
194
195 }
196
197 /**
198 * {@inheritDoc}
199 */
200 @Override
201 protected ObjectCreateRule createRule()
202 {
203 ObjectCreateRule objectCreateRule = new ObjectCreateRule( attributeName, type );
204
205 if ( constructorArgumentsType != null )
206 {
207 objectCreateRule.setConstructorArgumentTypes( constructorArgumentsType );
208 }
209 if ( defaultConstructorArguments != null )
210 {
211 objectCreateRule.setDefaultConstructorArguments( defaultConstructorArguments );
212 }
213
214 return objectCreateRule;
215 }
216
217 }