blob: 6f3a6825c68717d0c7ab27d8dbf44f606c074520 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.opensymphony.xwork2.ognl.accessor;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.ognl.OgnlUtil;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.ListPropertyAccessor;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Overrides the list property accessor so in the case of trying
* to add properties of a given bean and the JavaBean is not present,
* this class will create the necessary blank JavaBeans.
*
* @author Gabriel Zimmerman
*/
public class XWorkListPropertyAccessor extends ListPropertyAccessor {
private XWorkCollectionPropertyAccessor _sAcc = new XWorkCollectionPropertyAccessor();
private XWorkConverter xworkConverter;
private ObjectFactory objectFactory;
private ObjectTypeDeterminer objectTypeDeterminer;
private OgnlUtil ognlUtil;
private int autoGrowCollectionLimit = 255;
@Deprecated()
@Inject(value = "xwork.autoGrowCollectionLimit", required = false)
public void setDeprecatedAutoGrowCollectionLimit(String value) {
this.autoGrowCollectionLimit = Integer.valueOf(value);
}
@Inject(value = StrutsConstants.STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT, required = false)
public void setAutoGrowCollectionLimit(String value) {
this.autoGrowCollectionLimit = Integer.parseInt(value);
}
@Inject("java.util.Collection")
public void setXWorkCollectionPropertyAccessor(PropertyAccessor acc) {
this._sAcc = (XWorkCollectionPropertyAccessor) acc;
}
@Inject
public void setXWorkConverter(XWorkConverter conv) {
this.xworkConverter = conv;
}
@Inject
public void setObjectFactory(ObjectFactory fac) {
this.objectFactory = fac;
}
@Inject
public void setObjectTypeDeterminer(ObjectTypeDeterminer ot) {
this.objectTypeDeterminer = ot;
}
@Inject
public void setOgnlUtil(OgnlUtil util) {
this.ognlUtil = util;
}
@Override
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
if (ReflectionContextState.isGettingByKeyProperty(context)
|| name.equals(XWorkCollectionPropertyAccessor.KEY_PROPERTY_FOR_CREATION)) {
return _sAcc.getProperty(context, target, name);
} else if (name instanceof String) {
return super.getProperty(context, target, name);
}
ReflectionContextState.updateCurrentPropertyPath(context, name);
Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED);
if (name instanceof Number
&& ReflectionContextState.isCreatingNullObjects(context)
&& objectTypeDeterminer.shouldCreateIfNew(lastClass,lastProperty,target,null,true)) {
List list = (List) target;
int index = ((Number) name).intValue();
int listSize = list.size();
if (lastClass == null || lastProperty == null) {
return super.getProperty(context, target, name);
}
Class beanClass = objectTypeDeterminer.getElementClass(lastClass, lastProperty, name);
if (listSize <= index) {
Object result;
for (int i = listSize; i < index; i++) {
list.add(null);
}
try {
list.add(index, result = objectFactory.buildBean(beanClass, context));
} catch (Exception exc) {
throw new StrutsException(exc);
}
return result;
} else if (list.get(index) == null) {
Object result;
try {
list.set(index, result = objectFactory.buildBean(beanClass, context));
} catch (Exception exc) {
throw new StrutsException(exc);
}
return result;
}
}
return super.getProperty(context, target, name);
}
@Override
public void setProperty(Map context, Object target, Object name, Object value)
throws OgnlException {
Class lastClass = (Class) context.get(XWorkConverter.LAST_BEAN_CLASS_ACCESSED);
String lastProperty = (String) context.get(XWorkConverter.LAST_BEAN_PROPERTY_ACCESSED);
Class convertToClass = objectTypeDeterminer.getElementClass(lastClass, lastProperty, name);
if (name instanceof String && value.getClass().isArray()) {
// looks like the input game in the form of "someList.foo" and
// we are expected to define the index values ourselves.
// So let's do it:
Collection c = (Collection) target;
Object[] values = (Object[]) value;
for (Object v : values) {
try {
Object o = objectFactory.buildBean(convertToClass, context);
ognlUtil.setValue((String) name, context, o, v);
c.add(o);
} catch (Exception e) {
throw new OgnlException("Error converting given String values for Collection.", e);
}
}
// we don't want to do the normal list property setting now, since we've already done the work
// just return instead
return;
}
Object realValue = getRealValue(context, value, convertToClass);
if (target instanceof List && name instanceof Number) {
//make sure there are enough spaces in the List to set
List list = (List) target;
int listSize = list.size();
int count = ((Number) name).intValue();
if(count > autoGrowCollectionLimit)
throw new OgnlException("Error auto growing collection size to " + count + " which limited to "
+ autoGrowCollectionLimit);
if (count >= listSize) {
for (int i = listSize; i <= count; i++) {
list.add(null);
}
}
}
super.setProperty(context, target, name, realValue);
}
private Object getRealValue(Map context, Object value, Class convertToClass) {
if (value == null || convertToClass == null) {
return value;
}
return xworkConverter.convertValue(context, value, convertToClass);
}
}