001package 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 022import static java.lang.String.format; 023 024import java.util.Arrays; 025 026import org.apache.commons.digester3.ObjectCreateRule; 027 028/** 029 * Builder chained when invoking {@link LinkedRuleBuilder#createObject()}. 030 * 031 * @since 3.0 032 */ 033public 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}