Inject an attribute (name/value pair). If there is already an attribute with that name, this method turns the attribute into an AttributeList with both the previous and the new attribute as elements. This method will never alter a List that you inject. If you send in a {@link Lis
(String name, Object value)
| 215 | */ |
| 216 | |
| 217 | public synchronized ST add(String name, Object value) { |
| 218 | if ( name==null ) { |
| 219 | throw new NullPointerException("null attribute name"); |
| 220 | } |
| 221 | |
| 222 | if ( name.indexOf('.')>=0 ) { |
| 223 | throw new IllegalArgumentException("cannot have '.' in attribute names"); |
| 224 | } |
| 225 | |
| 226 | if ( STGroup.trackCreationEvents ) { |
| 227 | if ( debugState==null ) debugState = new ST.DebugState(); |
| 228 | debugState.addAttrEvents.map(name, new AddAttributeEvent(name, value)); |
| 229 | } |
| 230 | |
| 231 | FormalArgument arg = null; |
| 232 | if ( impl.hasFormalArgs ) { |
| 233 | if ( impl.formalArguments!=null ) arg = impl.formalArguments.get(name); |
| 234 | if ( arg==null ) { |
| 235 | throw new IllegalArgumentException("no such attribute: "+name); |
| 236 | } |
| 237 | } |
| 238 | else { |
| 239 | // define and make room in locals (a hack to make new ST("simple template") work.) |
| 240 | if ( impl.formalArguments!=null ) { |
| 241 | arg = impl.formalArguments.get(name); |
| 242 | } |
| 243 | |
| 244 | if ( arg==null ) { // not defined |
| 245 | arg = new FormalArgument(name); |
| 246 | impl.addArg(arg); |
| 247 | if ( locals==null ) locals = new Object[1]; |
| 248 | //else locals = Arrays.copyOf(locals, impl.formalArguments.size()); |
| 249 | else { |
| 250 | Object[] copy = new Object[impl.formalArguments.size()]; |
| 251 | System.arraycopy(locals, |
| 252 | 0, |
| 253 | copy, |
| 254 | 0, |
| 255 | Math.min(locals.length, impl.formalArguments.size())); |
| 256 | locals = copy; |
| 257 | } |
| 258 | locals[arg.index] = EMPTY_ATTR; |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | Object curvalue = locals[arg.index]; |
| 263 | if ( curvalue==EMPTY_ATTR ) { // new attribute |
| 264 | locals[arg.index] = value; |
| 265 | return this; |
| 266 | } |
| 267 | |
| 268 | // attribute will be multi-valued for sure now |
| 269 | // convert current attribute to list if not already |
| 270 | // copy-on-write semantics; copy a list injected by user to add new value |
| 271 | |
| 272 | AttributeList multi = convertToAttributeList(curvalue); |
| 273 | locals[arg.index] = multi; // replace with list |
| 274 |