data binding system polish; package improvements
This commit is contained in:
parent
f519406c37
commit
6c5fb23e79
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding;
|
||||
|
||||
/**
|
||||
* A factory for model property bindings.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface BindingFactory {
|
||||
|
||||
/**
|
||||
* The model object upon which bindings may be accessed.
|
||||
*/
|
||||
Object getModel();
|
||||
|
||||
/**
|
||||
* Get a binding to a model property.
|
||||
* @param property the property path
|
||||
* @throws NoSuchBindingException if no binding to the property exists
|
||||
*/
|
||||
Binding getBinding(String property);
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package org.springframework.ui.binding;
|
||||
|
||||
/**
|
||||
* Thrown by a BindingFactory when no binding to a property exists.
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* @see BindingFactory#getBinding(String)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NoSuchBindingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates a new no such binding exception.
|
||||
* @param property the requested property for which there is no binding
|
||||
*/
|
||||
public NoSuchBindingException(String property) {
|
||||
super("No binding to property '" + property + "' exists");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,24 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
import org.springframework.ui.binding.BindingResults;
|
||||
|
||||
class ArrayListBindingResults implements BindingResults {
|
||||
|
||||
|
|
@ -13,31 +13,25 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.binding;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.ui.binding.Binding;
|
||||
|
||||
/**
|
||||
* Binds user-entered values to properties of a model object.
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* @see #bind(String)
|
||||
* @see #getBinding(String)
|
||||
* @see #bind(Map)
|
||||
*/
|
||||
public interface Binder {
|
||||
|
||||
/**
|
||||
* The model object for which property bindings may be accessed.
|
||||
* The model this binder binds to.
|
||||
*/
|
||||
Object getModel();
|
||||
|
||||
/**
|
||||
* Get a binding to a model property..
|
||||
* @param property the property path
|
||||
* @throws NoSuchBindingException if no binding to the property exists
|
||||
*/
|
||||
Binding getBinding(String property);
|
||||
public Object getModel();
|
||||
|
||||
/**
|
||||
* Bind the source values to the properties of the model.
|
||||
|
|
@ -13,9 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.binding;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import org.springframework.ui.alert.Alert;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
|
||||
/**
|
||||
* The result of a bind operation.
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.binding;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -1,11 +1,22 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import org.springframework.ui.alert.Alert;
|
||||
import org.springframework.ui.alert.Severity;
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
|
||||
class BindingStatusResult implements BindingResult {
|
||||
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.binder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.convert.TypeConverter;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
import org.springframework.ui.binding.BindingFactory;
|
||||
import org.springframework.ui.binding.Binding.BindingStatus;
|
||||
import org.springframework.ui.binding.support.PropertyNotFoundException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A generic {@link Binder binder} suitable for use in most environments.
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* @see #setMessageSource(MessageSource)
|
||||
* @see #setTypeConverter(TypeConverter)
|
||||
* @see #bind(Map)
|
||||
*/
|
||||
public class GenericBinder implements Binder {
|
||||
|
||||
private BindingFactory bindingFactory;
|
||||
|
||||
private String[] requiredProperties;
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
public GenericBinder(BindingFactory bindingFactory) {
|
||||
Assert.notNull(bindingFactory, "The BindingFactory is required");
|
||||
this.bindingFactory = bindingFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the MessageSource that resolves localized {@link BindingResult} alert messages.
|
||||
* @param messageSource the message source
|
||||
*/
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
Assert.notNull(messageSource, "The MessageSource is required");
|
||||
this.messageSource = messageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the properties for which source values must be present in each bind attempt.
|
||||
* @param propertyPaths the property path expressions
|
||||
* @see MissingSourceValuesException
|
||||
*/
|
||||
public void setRequired(String[] propertyPaths) {
|
||||
this.requiredProperties = propertyPaths;
|
||||
}
|
||||
|
||||
public Object getModel() {
|
||||
return bindingFactory.getModel();
|
||||
}
|
||||
|
||||
protected Binding getBinding(String property) {
|
||||
return bindingFactory.getBinding(property);
|
||||
}
|
||||
|
||||
// implementing Binder
|
||||
|
||||
public BindingResults bind(Map<String, ? extends Object> sourceValues) {
|
||||
sourceValues = filter(sourceValues);
|
||||
checkRequired(sourceValues);
|
||||
ArrayListBindingResults results = new ArrayListBindingResults(sourceValues.size());
|
||||
for (Map.Entry<String, ? extends Object> sourceValue : sourceValues.entrySet()) {
|
||||
try {
|
||||
Binding binding = getBinding(sourceValue.getKey());
|
||||
results.add(bind(sourceValue, binding));
|
||||
} catch (PropertyNotFoundException e) {
|
||||
results.add(new PropertyNotFoundResult(sourceValue.getKey(), sourceValue.getValue(), messageSource));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Hook subclasses may use to filter the source values to bind.
|
||||
* This hook allows the binder to pre-process the source values before binding occurs.
|
||||
* For example, a Binder might insert empty or default values for fields that are not present.
|
||||
* As another example, a Binder might collapse multiple source values into a single source value.
|
||||
* @param sourceValues the original source values map provided by the caller
|
||||
* @return the filtered source values map that will be used to bind
|
||||
*/
|
||||
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> sourceValues) {
|
||||
return sourceValues;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private void checkRequired(Map<String, ? extends Object> sourceValues) {
|
||||
if (requiredProperties == null) {
|
||||
return;
|
||||
}
|
||||
List<String> missingRequired = new ArrayList<String>();
|
||||
for (String required : requiredProperties) {
|
||||
boolean found = false;
|
||||
for (String property : sourceValues.keySet()) {
|
||||
if (property.equals(required)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
missingRequired.add(required);
|
||||
}
|
||||
}
|
||||
if (!missingRequired.isEmpty()) {
|
||||
throw new MissingSourceValuesException(missingRequired, sourceValues);
|
||||
}
|
||||
}
|
||||
|
||||
private BindingResult bind(Map.Entry<String, ? extends Object> sourceValue, Binding binding) {
|
||||
String property = sourceValue.getKey();
|
||||
Object value = sourceValue.getValue();
|
||||
if (!binding.isEditable()) {
|
||||
return new PropertyNotEditableResult(property, value, messageSource);
|
||||
} else {
|
||||
binding.applySourceValue(value);
|
||||
if (binding.getStatus() == BindingStatus.DIRTY) {
|
||||
binding.commit();
|
||||
}
|
||||
return new BindingStatusResult(property, value, binding.getStatusAlert());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.binding;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -1,13 +1,24 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.ui.alert.Alert;
|
||||
import org.springframework.ui.alert.Severity;
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
import org.springframework.ui.message.MessageBuilder;
|
||||
import org.springframework.ui.message.ResolvableArgument;
|
||||
|
||||
|
|
@ -1,10 +1,24 @@
|
|||
package org.springframework.ui.binding.support;
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.binder;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.ui.alert.Alert;
|
||||
import org.springframework.ui.alert.Severity;
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
import org.springframework.ui.message.MessageBuilder;
|
||||
import org.springframework.ui.message.ResolvableArgument;
|
||||
|
||||
|
|
@ -13,11 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ui.binding.support;
|
||||
package org.springframework.ui.binding.binder;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.ui.binding.Binding;
|
||||
import org.springframework.ui.binding.BindingFactory;
|
||||
|
||||
/**
|
||||
* A binder designed for use in HTTP (web) environments.
|
||||
* Suited for binding user-provided HTTP query parameters to model properties.
|
||||
|
|
@ -36,8 +39,8 @@ public class WebBinder extends GenericBinder {
|
|||
* Creates a new web binder for the model object.
|
||||
* @param model the model object containing properties this binder will bind to
|
||||
*/
|
||||
public WebBinder(Object model) {
|
||||
super(model);
|
||||
public WebBinder(BindingFactory bindingFactory) {
|
||||
super(bindingFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -72,7 +75,7 @@ public class WebBinder extends GenericBinder {
|
|||
} else if (field.startsWith(presentPrefix)) {
|
||||
field = field.substring(presentPrefix.length());
|
||||
if (!sourceValues.containsKey(field) && !sourceValues.containsKey(defaultPrefix + field)) {
|
||||
value = getEmptyValue((PropertyBinding) getBinding(field));
|
||||
value = getEmptyValue(getBinding(field));
|
||||
filteredValues.put(field, value);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -82,8 +85,8 @@ public class WebBinder extends GenericBinder {
|
|||
return filteredValues;
|
||||
}
|
||||
|
||||
protected Object getEmptyValue(PropertyBinding binding) {
|
||||
Class<?> type = binding.getValueModel().getValueType();
|
||||
protected Object getEmptyValue(Binding binding) {
|
||||
Class<?> type = binding.getValueType();
|
||||
if (boolean.class.equals(type) || Boolean.class.equals(type)) {
|
||||
return Boolean.FALSE;
|
||||
} else {
|
||||
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.config;
|
||||
|
||||
public interface Condition {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.convert.TypeConverter;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
import org.springframework.ui.binding.config.Condition;
|
||||
import org.springframework.ui.format.Formatter;
|
||||
|
||||
public interface BindingContext {
|
||||
|
||||
MessageSource getMessageSource();
|
||||
|
||||
TypeConverter getTypeConverter();
|
||||
|
||||
Condition getEditableCondition();
|
||||
|
||||
Condition getEnabledCondition();
|
||||
|
||||
Condition getVisibleCondition();
|
||||
|
||||
Binding getBinding(String property);
|
||||
|
||||
Formatter getFormatter();
|
||||
|
||||
Formatter getElementFormatter();
|
||||
|
||||
Formatter getKeyFormatter();
|
||||
|
||||
Binding getListElementBinding(int index);
|
||||
|
||||
Binding getMapValueBinding(Object key);
|
||||
|
||||
String getLabel();
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import org.springframework.ui.binding.config.Condition;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,54 +1,31 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.ui.format.Formatter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// TODO should this delegate to type converter...
|
||||
class DefaultFormatter implements Formatter {
|
||||
|
||||
public static final Formatter INSTANCE = new DefaultFormatter();
|
||||
|
||||
public static final Formatter COLLECTION_FORMATTER = new Formatter() {
|
||||
public String format(Object object, Locale locale) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
} else {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if (object.getClass().isArray()) {
|
||||
int length = Array.getLength(object);
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer.append(INSTANCE.format(Array.get(object, i), locale));
|
||||
if (i < length - 1) {
|
||||
buffer.append(",");
|
||||
}
|
||||
}
|
||||
} else if (Collection.class.isAssignableFrom(object.getClass())) {
|
||||
Collection c = (Collection) object;
|
||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||
buffer.append(INSTANCE.format(it.next(), locale));
|
||||
if (it.hasNext()) {
|
||||
buffer.append(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public Object parse(String formatted, Locale locale) throws ParseException {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public String format(Object object, Locale locale) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -1,11 +1,27 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
|
@ -19,12 +35,13 @@ import org.springframework.core.style.StylerUtils;
|
|||
import org.springframework.ui.alert.Alert;
|
||||
import org.springframework.ui.alert.Severity;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
import org.springframework.ui.binding.support.GenericBinder.BindingContext;
|
||||
import org.springframework.ui.format.Formatter;
|
||||
import org.springframework.ui.message.MessageBuilder;
|
||||
import org.springframework.ui.message.ResolvableArgument;
|
||||
|
||||
public abstract class AbstractBinding implements Binding {
|
||||
public class GenericBinding implements Binding {
|
||||
|
||||
private ValueModel valueModel;
|
||||
|
||||
private BindingContext bindingContext;
|
||||
|
||||
|
|
@ -36,9 +53,10 @@ public abstract class AbstractBinding implements Binding {
|
|||
|
||||
private Exception invalidSourceValueCause;
|
||||
|
||||
public AbstractBinding(BindingContext bindingContext) {
|
||||
public GenericBinding(ValueModel valueModel, BindingContext bindingContext) {
|
||||
this.valueModel = valueModel;
|
||||
this.bindingContext = bindingContext;
|
||||
buffer = new ValueBuffer(getValueModel());
|
||||
buffer = new ValueBuffer(valueModel);
|
||||
status = BindingStatus.CLEAN;
|
||||
}
|
||||
|
||||
|
|
@ -52,16 +70,16 @@ public abstract class AbstractBinding implements Binding {
|
|||
if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) {
|
||||
return buffer.getValue();
|
||||
} else {
|
||||
return getValueModel().getValue();
|
||||
return valueModel.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> getValueType() {
|
||||
return getValueModel().getValueType();
|
||||
return valueModel.getValueType();
|
||||
}
|
||||
|
||||
public boolean isEditable() {
|
||||
return bindingContext.getEditableCondition().isTrue();
|
||||
return valueModel.isWriteable() && bindingContext.getEditableCondition().isTrue();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
|
|
@ -91,17 +109,20 @@ public abstract class AbstractBinding implements Binding {
|
|||
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||
}
|
||||
} else if (sourceValue instanceof String[]) {
|
||||
Object parsed;
|
||||
if (isMap()) {
|
||||
String[] sourceValues = (String[]) sourceValue;
|
||||
Class<?> parsedType = getFormattedObjectType(bindingContext.getElementFormatter().getClass());
|
||||
if (parsedType == null) {
|
||||
parsedType = String.class;
|
||||
}
|
||||
Object parsed = Array.newInstance(parsedType, sourceValues.length);
|
||||
Formatter keyFormatter = bindingContext.getKeyFormatter();
|
||||
Formatter valueFormatter = bindingContext.getElementFormatter();
|
||||
Map map = new LinkedHashMap(sourceValues.length);
|
||||
for (int i = 0; i < sourceValues.length; i++) {
|
||||
String entryString = sourceValues[i];
|
||||
Object parsedValue;
|
||||
try {
|
||||
parsedValue = bindingContext.getElementFormatter().parse(sourceValues[i], getLocale());
|
||||
Array.set(parsed, i, parsedValue);
|
||||
String[] keyValue = entryString.split("=");
|
||||
Object parsedMapKey = keyFormatter.parse(keyValue[0], getLocale());
|
||||
Object parsedMapValue = valueFormatter.parse(keyValue[1], getLocale());
|
||||
map.put(parsedMapKey, parsedMapValue);
|
||||
} catch (ParseException e) {
|
||||
this.sourceValue = sourceValue;
|
||||
invalidSourceValueCause = e;
|
||||
|
|
@ -109,6 +130,24 @@ public abstract class AbstractBinding implements Binding {
|
|||
break;
|
||||
}
|
||||
}
|
||||
parsed = map;
|
||||
} else {
|
||||
String[] sourceValues = (String[]) sourceValue;
|
||||
List list = new ArrayList(sourceValues.length);
|
||||
for (int i = 0; i < sourceValues.length; i++) {
|
||||
Object parsedValue;
|
||||
try {
|
||||
parsedValue = bindingContext.getElementFormatter().parse(sourceValues[i], getLocale());
|
||||
list.add(parsedValue);
|
||||
} catch (ParseException e) {
|
||||
this.sourceValue = sourceValue;
|
||||
invalidSourceValueCause = e;
|
||||
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parsed = list;
|
||||
}
|
||||
if (status != BindingStatus.INVALID_SOURCE_VALUE) {
|
||||
try {
|
||||
buffer.setValue(coerseToValueType(parsed));
|
||||
|
|
@ -256,6 +295,13 @@ public abstract class AbstractBinding implements Binding {
|
|||
}
|
||||
|
||||
public Binding getMapValueBinding(Object key) {
|
||||
if (key instanceof String) {
|
||||
try {
|
||||
key = bindingContext.getKeyFormatter().parse((String) key, getLocale());
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Unable to parse map key '" + key + "'", e);
|
||||
}
|
||||
}
|
||||
return bindingContext.getMapValueBinding(key);
|
||||
}
|
||||
|
||||
|
|
@ -263,31 +309,25 @@ public abstract class AbstractBinding implements Binding {
|
|||
public String formatValue(Object value) {
|
||||
Formatter formatter;
|
||||
if (Collection.class.isAssignableFrom(getValueType()) || getValueType().isArray() || isMap()) {
|
||||
formatter = getBindingContext().getElementFormatter();
|
||||
formatter = bindingContext.getElementFormatter();
|
||||
} else {
|
||||
formatter = getBindingContext().getFormatter();
|
||||
formatter = bindingContext.getFormatter();
|
||||
}
|
||||
return format(value, formatter);
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
// internal helpers
|
||||
|
||||
protected BindingContext getBindingContext() {
|
||||
return bindingContext;
|
||||
}
|
||||
|
||||
protected abstract ValueModel getValueModel();
|
||||
|
||||
protected Locale getLocale() {
|
||||
return LocaleContextHolder.getLocale();
|
||||
}
|
||||
|
||||
protected String format(Object value, Formatter formatter) {
|
||||
private String format(Object value, Formatter formatter) {
|
||||
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
||||
value = bindingContext.getTypeConverter().convert(value, formattedType);
|
||||
return formatter.format(value, getLocale());
|
||||
}
|
||||
|
||||
private Locale getLocale() {
|
||||
return LocaleContextHolder.getLocale();
|
||||
}
|
||||
|
||||
private Class getFormattedObjectType(Class formatterClass) {
|
||||
Class classToIntrospect = formatterClass;
|
||||
while (classToIntrospect != null) {
|
||||
|
|
@ -317,7 +357,7 @@ public abstract class AbstractBinding implements Binding {
|
|||
}
|
||||
|
||||
private Object coerseToValueType(Object parsed) {
|
||||
TypeDescriptor targetType = getValueModel().getValueTypeDescriptor();
|
||||
TypeDescriptor targetType = valueModel.getValueTypeDescriptor();
|
||||
TypeConverter converter = bindingContext.getTypeConverter();
|
||||
if (parsed != null && converter.canConvert(parsed.getClass(), targetType)) {
|
||||
return converter.convert(parsed, targetType);
|
||||
|
|
@ -338,39 +378,10 @@ public abstract class AbstractBinding implements Binding {
|
|||
}
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
static abstract class AbstractAlert implements Alert {
|
||||
public String toString() {
|
||||
return getCode() + " - " + getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For accessing the raw bound model object.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ValueModel {
|
||||
|
||||
/**
|
||||
* The model value.
|
||||
*/
|
||||
Object getValue();
|
||||
|
||||
/**
|
||||
* The model value type.
|
||||
*/
|
||||
Class<?> getValueType();
|
||||
|
||||
/**
|
||||
* The model value type descriptor.
|
||||
*/
|
||||
TypeDescriptor<?> getValueTypeDescriptor();
|
||||
|
||||
/**
|
||||
* Set the model value.
|
||||
*/
|
||||
void setValue(Object value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,19 +21,19 @@ import java.beans.Introspector;
|
|||
import java.beans.PropertyDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.groovy.binding.PropertyBinding;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.convert.TypeConverter;
|
||||
import org.springframework.core.convert.support.DefaultTypeConverter;
|
||||
import org.springframework.ui.binding.Binder;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
import org.springframework.ui.binding.BindingResults;
|
||||
import org.springframework.ui.binding.MissingSourceValuesException;
|
||||
import org.springframework.ui.binding.Binding.BindingStatus;
|
||||
import org.springframework.ui.binding.BindingFactory;
|
||||
import org.springframework.ui.binding.binder.Binder;
|
||||
import org.springframework.ui.binding.binder.BindingResult;
|
||||
import org.springframework.ui.binding.config.BindingRuleConfiguration;
|
||||
import org.springframework.ui.binding.config.Condition;
|
||||
import org.springframework.ui.format.Formatter;
|
||||
|
|
@ -47,7 +47,7 @@ import org.springframework.util.Assert;
|
|||
* @see #setTypeConverter(TypeConverter)
|
||||
* @see #bind(Map)
|
||||
*/
|
||||
public class GenericBinder implements Binder {
|
||||
public class GenericBindingFactory implements BindingFactory {
|
||||
|
||||
private Object model;
|
||||
|
||||
|
|
@ -59,13 +59,11 @@ public class GenericBinder implements Binder {
|
|||
|
||||
private MessageSource messageSource;
|
||||
|
||||
private String[] requiredProperties = new String[0];
|
||||
|
||||
/**
|
||||
* Creates a new binder for the model object.
|
||||
* @param model the model object containing properties this binder will bind to
|
||||
*/
|
||||
public GenericBinder(Object model) {
|
||||
public GenericBindingFactory(Object model) {
|
||||
Assert.notNull(model, "The model to bind to is required");
|
||||
this.model = model;
|
||||
bindingRules = new HashMap<String, GenericBindingRule>();
|
||||
|
|
@ -104,9 +102,9 @@ public class GenericBinder implements Binder {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add a new binding rule for the property at the path specified.
|
||||
* @param propertyPath binding rule property path in format prop.nestedProp
|
||||
* @return
|
||||
* @return a builder for the binding rule
|
||||
*/
|
||||
public BindingRuleConfiguration bindingRule(String propertyPath) {
|
||||
PropertyPath path = new PropertyPath(propertyPath);
|
||||
|
|
@ -142,55 +140,6 @@ public class GenericBinder implements Binder {
|
|||
return binding;
|
||||
}
|
||||
|
||||
public BindingResults bind(Map<String, ? extends Object> sourceValues) {
|
||||
sourceValues = filter(sourceValues);
|
||||
checkRequired(sourceValues);
|
||||
ArrayListBindingResults results = new ArrayListBindingResults(sourceValues.size());
|
||||
for (Map.Entry<String, ? extends Object> sourceValue : sourceValues.entrySet()) {
|
||||
try {
|
||||
Binding binding = getBinding(sourceValue.getKey());
|
||||
results.add(bind(sourceValue, binding));
|
||||
} catch (PropertyNotFoundException e) {
|
||||
results.add(new PropertyNotFoundResult(sourceValue.getKey(), sourceValue.getValue(), messageSource));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Hook subclasses may use to filter the source values to bind.
|
||||
* This hook allows the binder to pre-process the source values before binding occurs.
|
||||
* For example, a Binder might insert empty or default values for fields that are not present.
|
||||
* As another example, a Binder might collapse multiple source values into a single source value.
|
||||
* @param sourceValues the original source values map provided by the caller
|
||||
* @return the filtered source values map that will be used to bind
|
||||
*/
|
||||
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> sourceValues) {
|
||||
return sourceValues;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private void checkRequired(Map<String, ? extends Object> sourceValues) {
|
||||
List<String> missingRequired = new ArrayList<String>();
|
||||
for (String required : requiredProperties) {
|
||||
boolean found = false;
|
||||
for (String property : sourceValues.keySet()) {
|
||||
if (property.equals(required)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
missingRequired.add(required);
|
||||
}
|
||||
}
|
||||
if (!missingRequired.isEmpty()) {
|
||||
throw new MissingSourceValuesException(missingRequired, sourceValues);
|
||||
}
|
||||
}
|
||||
|
||||
private GenericBindingRule getBindingRule(String property) {
|
||||
GenericBindingRule rule = bindingRules.get(property);
|
||||
if (rule == null) {
|
||||
|
|
@ -200,20 +149,6 @@ public class GenericBinder implements Binder {
|
|||
return rule;
|
||||
}
|
||||
|
||||
private BindingResult bind(Map.Entry<String, ? extends Object> sourceValue, Binding binding) {
|
||||
String property = sourceValue.getKey();
|
||||
Object value = sourceValue.getValue();
|
||||
if (!binding.isEditable()) {
|
||||
return new PropertyNotEditableResult(property, value, messageSource);
|
||||
} else {
|
||||
binding.applySourceValue(value);
|
||||
if (binding.getStatus() == BindingStatus.DIRTY) {
|
||||
binding.commit();
|
||||
}
|
||||
return new BindingStatusResult(property, value, binding.getStatusAlert());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
class GenericBindingRule implements BindingRuleConfiguration, BindingContext {
|
||||
|
||||
|
|
@ -223,10 +158,10 @@ public class GenericBinder implements Binder {
|
|||
|
||||
private Formatter formatter;
|
||||
|
||||
private Formatter elementFormatter;
|
||||
|
||||
private Formatter keyFormatter;
|
||||
|
||||
private Formatter elementFormatter;
|
||||
|
||||
private Condition editableCondition = Condition.ALWAYS_TRUE;
|
||||
|
||||
private Condition enabledCondition = Condition.ALWAYS_TRUE;
|
||||
|
|
@ -239,6 +174,8 @@ public class GenericBinder implements Binder {
|
|||
|
||||
private Map<Integer, Binding> listElementBindings;
|
||||
|
||||
private Map<Object, Binding> mapValueBindings;
|
||||
|
||||
public GenericBindingRule(String property, Class modelClass) {
|
||||
this.modelClass = modelClass;
|
||||
this.property = findPropertyDescriptor(property);
|
||||
|
|
@ -262,14 +199,6 @@ public class GenericBinder implements Binder {
|
|||
}
|
||||
}
|
||||
|
||||
public Formatter<?> getElementFormatter() {
|
||||
if (elementFormatter != null) {
|
||||
return formatter;
|
||||
} else {
|
||||
return formatterRegistry.getFormatter(getElementType());
|
||||
}
|
||||
}
|
||||
|
||||
public Formatter<?> getKeyFormatter() {
|
||||
if (keyFormatter != null) {
|
||||
return keyFormatter;
|
||||
|
|
@ -278,6 +207,14 @@ public class GenericBinder implements Binder {
|
|||
}
|
||||
}
|
||||
|
||||
public Formatter<?> getElementFormatter() {
|
||||
if (elementFormatter != null) {
|
||||
return formatter;
|
||||
} else {
|
||||
return formatterRegistry.getFormatter(getElementType());
|
||||
}
|
||||
}
|
||||
|
||||
public Condition getEnabledCondition() {
|
||||
return enabledCondition;
|
||||
}
|
||||
|
|
@ -295,79 +232,34 @@ public class GenericBinder implements Binder {
|
|||
return getBindingRule(property, binding.getValueType()).getBinding(binding.getValue());
|
||||
}
|
||||
|
||||
public Binding getListElementBinding(final int index) {
|
||||
public Binding getListElementBinding(int index) {
|
||||
if (listElementBindings == null) {
|
||||
listElementBindings = new HashMap<Integer, Binding>();
|
||||
}
|
||||
growListIfNecessary(index);
|
||||
Binding binding = listElementBindings.get(index);
|
||||
if (binding == null) {
|
||||
final Map<String, Binding> nestedBindings = new HashMap<String, Binding>();
|
||||
BindingContext listContext = new BindingContext() {
|
||||
public MessageSource getMessageSource() {
|
||||
return GenericBindingRule.this.getMessageSource();
|
||||
}
|
||||
|
||||
public TypeConverter getTypeConverter() {
|
||||
return GenericBindingRule.this.getTypeConverter();
|
||||
}
|
||||
|
||||
public Binding getBinding(String property) {
|
||||
GenericBindingRule rule = GenericBindingRule.this.getBindingRule(property, getElementType());
|
||||
Object model = ((List) GenericBindingRule.this.binding.getValue()).get(index);
|
||||
Binding binding = nestedBindings.get(property);
|
||||
if (binding == null) {
|
||||
binding = new PropertyBinding(rule.property, model, rule);
|
||||
nestedBindings.put(property, binding);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public Formatter getFormatter() {
|
||||
return GenericBindingRule.this.getElementFormatter();
|
||||
}
|
||||
|
||||
public Formatter getElementFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Formatter getKeyFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Condition getEditableCondition() {
|
||||
return GenericBindingRule.this.getEditableCondition();
|
||||
}
|
||||
|
||||
public Condition getEnabledCondition() {
|
||||
return GenericBindingRule.this.getEnabledCondition();
|
||||
}
|
||||
|
||||
public Condition getVisibleCondition() {
|
||||
return GenericBindingRule.this.getVisibleCondition();
|
||||
}
|
||||
|
||||
public Binding getListElementBinding(int index) {
|
||||
throw new IllegalArgumentException("Not yet supported");
|
||||
}
|
||||
|
||||
public Binding getMapValueBinding(Object key) {
|
||||
throw new IllegalArgumentException("Not yet supported");
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return GenericBindingRule.this.getLabel() + "[" + index + "]";
|
||||
}
|
||||
|
||||
};
|
||||
binding = new ListElementBinding(index, getElementType(), (List) this.binding.getValue(), listContext);
|
||||
BindingContext bindingContext = new ListElementBindingContext(index, this);
|
||||
ValueModel valueModel = new ListElementValueModel(index, getElementType(), (List) this.binding.getValue());
|
||||
binding = new GenericBinding(valueModel, bindingContext);
|
||||
listElementBindings.put(index, binding);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public Binding getMapValueBinding(Object key) {
|
||||
return null;
|
||||
if (mapValueBindings == null) {
|
||||
mapValueBindings = new HashMap<Object, Binding>();
|
||||
}
|
||||
createMapValueIfNecessary();
|
||||
Binding binding = mapValueBindings.get(key);
|
||||
if (binding == null) {
|
||||
BindingContext bindingContext = new MapValueBindingContext(key, this);
|
||||
ValueModel valueModel = new MapValueValueModel(key, getElementType(), (Map) this.binding.getValue(), bindingContext);
|
||||
binding = new GenericBinding(valueModel, bindingContext);
|
||||
mapValueBindings.put(key, binding);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
|
|
@ -416,8 +308,12 @@ public class GenericBinder implements Binder {
|
|||
// internal helpers
|
||||
|
||||
private Class<?> getElementType() {
|
||||
if (Map.class.isAssignableFrom(property.getPropertyType())) {
|
||||
return GenericCollectionTypeResolver.getMapValueReturnType(property.getReadMethod());
|
||||
} else {
|
||||
return GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> getKeyType() {
|
||||
return GenericCollectionTypeResolver.getMapKeyReturnType(property.getReadMethod());
|
||||
|
|
@ -443,7 +339,8 @@ public class GenericBinder implements Binder {
|
|||
|
||||
Binding getBinding(Object model) {
|
||||
if (binding == null) {
|
||||
binding = new PropertyBinding(property, model, this);
|
||||
PropertyValueModel valueModel = new PropertyValueModel(property, model);
|
||||
binding = new GenericBinding(valueModel, this);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
|
@ -475,6 +372,15 @@ public class GenericBinder implements Binder {
|
|||
}
|
||||
}
|
||||
|
||||
private void createMapValueIfNecessary() {
|
||||
Object value = binding.getValue();
|
||||
if (value == null) {
|
||||
value = newMapValue(binding.getValueType());
|
||||
binding.applySourceValue(value);
|
||||
binding.commit();
|
||||
}
|
||||
}
|
||||
|
||||
private void growListIfNecessary(int index) {
|
||||
List list = (List) binding.getValue();
|
||||
if (list == null) {
|
||||
|
|
@ -490,6 +396,14 @@ public class GenericBinder implements Binder {
|
|||
}
|
||||
}
|
||||
|
||||
private Map newMapValue(Class<?> type) {
|
||||
if (type.isInterface()) {
|
||||
return (Map) newValue(LinkedHashMap.class);
|
||||
} else {
|
||||
return (Map) newValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
private List newListValue(Class<?> type) {
|
||||
if (type.isInterface()) {
|
||||
return (List) newValue(ArrayList.class);
|
||||
|
|
@ -510,36 +424,153 @@ public class GenericBinder implements Binder {
|
|||
|
||||
}
|
||||
|
||||
public interface BindingContext {
|
||||
private static class ListElementBindingContext implements BindingContext {
|
||||
|
||||
MessageSource getMessageSource();
|
||||
private int index;
|
||||
|
||||
TypeConverter getTypeConverter();
|
||||
private GenericBindingRule listBindingContext;
|
||||
|
||||
Condition getEditableCondition();
|
||||
|
||||
Condition getEnabledCondition();
|
||||
|
||||
Condition getVisibleCondition();
|
||||
|
||||
Binding getBinding(String property);
|
||||
|
||||
Formatter getFormatter();
|
||||
|
||||
Formatter getElementFormatter();
|
||||
|
||||
Formatter getKeyFormatter();
|
||||
|
||||
Binding getListElementBinding(int index);
|
||||
|
||||
Binding getMapValueBinding(Object key);
|
||||
|
||||
String getLabel();
|
||||
final Map<String, Binding> nestedBindings = new HashMap<String, Binding>();
|
||||
|
||||
public ListElementBindingContext(int index, GenericBindingRule listBindingContext) {
|
||||
this.index = index;
|
||||
this.listBindingContext = listBindingContext;
|
||||
}
|
||||
|
||||
public void setRequired(String[] propertyPaths) {
|
||||
this.requiredProperties = propertyPaths;
|
||||
public MessageSource getMessageSource() {
|
||||
return listBindingContext.getMessageSource();
|
||||
}
|
||||
|
||||
public TypeConverter getTypeConverter() {
|
||||
return listBindingContext.getTypeConverter();
|
||||
}
|
||||
|
||||
public Binding getBinding(String property) {
|
||||
Object model = ((List) listBindingContext.binding.getValue()).get(index);
|
||||
Class<?> elementType = listBindingContext.getElementType();
|
||||
if (elementType == null) {
|
||||
elementType = model.getClass();
|
||||
}
|
||||
GenericBindingRule rule = listBindingContext.getBindingRule(property, elementType);
|
||||
Binding binding = nestedBindings.get(property);
|
||||
if (binding == null) {
|
||||
PropertyValueModel valueModel = new PropertyValueModel(rule.property, model);
|
||||
binding = new GenericBinding(valueModel, rule);
|
||||
nestedBindings.put(property, binding);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public Formatter getFormatter() {
|
||||
return listBindingContext.getElementFormatter();
|
||||
}
|
||||
|
||||
public Formatter getElementFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Formatter getKeyFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Condition getEditableCondition() {
|
||||
return listBindingContext.getEditableCondition();
|
||||
}
|
||||
|
||||
public Condition getEnabledCondition() {
|
||||
return listBindingContext.getEnabledCondition();
|
||||
}
|
||||
|
||||
public Condition getVisibleCondition() {
|
||||
return listBindingContext.getVisibleCondition();
|
||||
}
|
||||
|
||||
public Binding getListElementBinding(int index) {
|
||||
throw new IllegalArgumentException("Not yet supported");
|
||||
}
|
||||
|
||||
public Binding getMapValueBinding(Object key) {
|
||||
throw new IllegalArgumentException("Not yet supported");
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return listBindingContext.getLabel() + "[" + index + "]";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private static class MapValueBindingContext implements BindingContext {
|
||||
|
||||
private Object key;
|
||||
|
||||
private GenericBindingRule mapBindingContext;
|
||||
|
||||
final Map<String, Binding> nestedBindings = new HashMap<String, Binding>();
|
||||
|
||||
public MapValueBindingContext(Object key, GenericBindingRule mapBindingContext) {
|
||||
this.key = key;
|
||||
this.mapBindingContext = mapBindingContext;
|
||||
}
|
||||
|
||||
public MessageSource getMessageSource() {
|
||||
return mapBindingContext.getMessageSource();
|
||||
}
|
||||
|
||||
public TypeConverter getTypeConverter() {
|
||||
return mapBindingContext.getTypeConverter();
|
||||
}
|
||||
|
||||
public Binding getBinding(String property) {
|
||||
Object model = ((Map) mapBindingContext.binding.getValue()).get(key);
|
||||
Class<?> elementType = mapBindingContext.getElementType();
|
||||
if (elementType == null) {
|
||||
elementType = model.getClass();
|
||||
}
|
||||
GenericBindingRule rule = mapBindingContext.getBindingRule(property, elementType);
|
||||
Binding binding = nestedBindings.get(property);
|
||||
if (binding == null) {
|
||||
PropertyValueModel valueModel = new PropertyValueModel(rule.property, model);
|
||||
binding = new GenericBinding(valueModel, rule);
|
||||
nestedBindings.put(property, binding);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public Formatter getFormatter() {
|
||||
return mapBindingContext.getElementFormatter();
|
||||
}
|
||||
|
||||
public Formatter getElementFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Formatter getKeyFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Condition getEditableCondition() {
|
||||
return mapBindingContext.getEditableCondition();
|
||||
}
|
||||
|
||||
public Condition getEnabledCondition() {
|
||||
return mapBindingContext.getEnabledCondition();
|
||||
}
|
||||
|
||||
public Condition getVisibleCondition() {
|
||||
return mapBindingContext.getVisibleCondition();
|
||||
}
|
||||
|
||||
public Binding getListElementBinding(int index) {
|
||||
throw new IllegalArgumentException("Not yet supported");
|
||||
}
|
||||
|
||||
public Binding getMapValueBinding(Object key) {
|
||||
throw new IllegalArgumentException("Not yet supported");
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return mapBindingContext.getLabel() + "[" + key + "]";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -17,20 +17,31 @@ package org.springframework.ui.binding.support;
|
|||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.TypeConverter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.ConversionUtils;
|
||||
import org.springframework.core.convert.support.DefaultTypeConverter;
|
||||
import org.springframework.ui.format.AnnotationFormatterFactory;
|
||||
import org.springframework.ui.format.Formatted;
|
||||
import org.springframework.ui.format.Formatter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A generic implementation of {@link FormatterRegistry} suitable for use in most binding environments.
|
||||
|
|
@ -48,7 +59,14 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
|||
|
||||
private Map<Class, AnnotationFormatterFactory> annotationFormatters = new HashMap<Class, AnnotationFormatterFactory>();
|
||||
|
||||
private TypeConverter typeConverter = new DefaultTypeConverter();
|
||||
|
||||
public void setTypeConverter(TypeConverter typeConverter) {
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
public Formatter<?> getFormatter(PropertyDescriptor property) {
|
||||
Assert.notNull(property, "The PropertyDescriptor is required");
|
||||
TypeDescriptor<?> propertyType = new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
|
||||
Annotation[] annotations = propertyType.getAnnotations();
|
||||
for (Annotation a : annotations) {
|
||||
|
|
@ -60,11 +78,13 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
|||
Formatter<?> formatter = null;
|
||||
Class<?> type;
|
||||
if (propertyType.isCollection() || propertyType.isArray()) {
|
||||
formatter = collectionTypeFormatters.get(new GenericCollectionPropertyType(propertyType.getType(), propertyType.getElementType()));
|
||||
GenericCollectionPropertyType collectionType = new GenericCollectionPropertyType(propertyType.getType(),
|
||||
propertyType.getElementType());
|
||||
formatter = collectionTypeFormatters.get(collectionType);
|
||||
if (formatter != null) {
|
||||
return formatter;
|
||||
} else {
|
||||
return DefaultFormatter.COLLECTION_FORMATTER;
|
||||
return new DefaultCollectionFormatter(collectionType, this);
|
||||
}
|
||||
} else {
|
||||
type = propertyType.getType();
|
||||
|
|
@ -73,6 +93,7 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
|||
}
|
||||
|
||||
public Formatter<?> getFormatter(Class<?> type) {
|
||||
Assert.notNull(type, "The Class of the object to format is required");
|
||||
Formatter formatter = typeFormatters.get(type);
|
||||
if (formatter != null) {
|
||||
return formatter;
|
||||
|
|
@ -83,20 +104,20 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
|||
try {
|
||||
formatter = (Formatter) formatterClass.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
// TODO better runtime exception
|
||||
throw new IllegalStateException(e);
|
||||
throw new IllegalStateException(
|
||||
"Formatter referenced by @Formatted annotation does not have default constructor", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
throw new IllegalStateException(
|
||||
"Formatter referenced by @Formatted annotation does not have public constructor", e);
|
||||
}
|
||||
typeFormatters.put(type, formatter);
|
||||
return formatter;
|
||||
} else {
|
||||
return DefaultFormatter.INSTANCE;
|
||||
return new DefaultFormatter(type, typeConverter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void add(Class<?> propertyType, Formatter<?> formatter) {
|
||||
if (propertyType.isAnnotation()) {
|
||||
annotationFormatters.put(propertyType, new SimpleAnnotationFormatterFactory(formatter));
|
||||
|
|
@ -159,4 +180,124 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
|||
|
||||
}
|
||||
|
||||
private static class DefaultFormatter implements Formatter {
|
||||
|
||||
public static final Formatter DEFAULT_INSTANCE = new DefaultFormatter(null, null);
|
||||
|
||||
private Class<?> objectType;
|
||||
|
||||
private TypeConverter typeConverter;
|
||||
|
||||
public DefaultFormatter(Class<?> objectType, TypeConverter typeConverter) {
|
||||
this.objectType = objectType;
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
public String format(Object object, Locale locale) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
} else {
|
||||
if (typeConverter != null && typeConverter.canConvert(object.getClass(), String.class)) {
|
||||
return typeConverter.convert(object, String.class);
|
||||
} else {
|
||||
return object.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object parse(String formatted, Locale locale) throws ParseException {
|
||||
if (formatted == "") {
|
||||
return null;
|
||||
} else {
|
||||
if (typeConverter != null && typeConverter.canConvert(String.class, objectType)) {
|
||||
try {
|
||||
return typeConverter.convert(formatted, objectType);
|
||||
} catch (ConversionFailedException e) {
|
||||
throw new ParseException(formatted, -1);
|
||||
}
|
||||
} else {
|
||||
return formatted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultCollectionFormatter implements Formatter {
|
||||
|
||||
private GenericCollectionPropertyType collectionType;
|
||||
|
||||
private Formatter elementFormatter;
|
||||
|
||||
public DefaultCollectionFormatter(GenericCollectionPropertyType collectionType,
|
||||
GenericFormatterRegistry formatterRegistry) {
|
||||
this.collectionType = collectionType;
|
||||
this.elementFormatter = collectionType.getElementType() != null ? formatterRegistry
|
||||
.getFormatter(collectionType.getElementType()) : DefaultFormatter.DEFAULT_INSTANCE;
|
||||
}
|
||||
|
||||
public String format(Object object, Locale locale) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
} else {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if (object.getClass().isArray()) {
|
||||
int length = Array.getLength(object);
|
||||
for (int i = 0; i < length; i++) {
|
||||
buffer.append(elementFormatter.format(Array.get(object, i), locale));
|
||||
if (i < length - 1) {
|
||||
buffer.append(",");
|
||||
}
|
||||
}
|
||||
} else if (Collection.class.isAssignableFrom(object.getClass())) {
|
||||
Collection c = (Collection) object;
|
||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||
buffer.append(elementFormatter.format(it.next(), locale));
|
||||
if (it.hasNext()) {
|
||||
buffer.append(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public Object parse(String formatted, Locale locale) throws ParseException {
|
||||
String[] fields = StringUtils.commaDelimitedListToStringArray(formatted);
|
||||
if (collectionType.getCollectionType().isArray()) {
|
||||
Object array = Array.newInstance(getElementType(), fields.length);
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Array.set(array, i, elementFormatter.parse(fields[i], locale));
|
||||
}
|
||||
return array;
|
||||
} else {
|
||||
Collection collection = newCollection();
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
collection.add(elementFormatter.parse(fields[i], locale));
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> getElementType() {
|
||||
if (collectionType.getElementType() != null) {
|
||||
return collectionType.getElementType();
|
||||
} else {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection newCollection() {
|
||||
try {
|
||||
Class<? extends Collection> implType = ConversionUtils
|
||||
.getCollectionImpl((Class<? extends Collection>) collectionType.getCollectionType());
|
||||
return (Collection) implType.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new IllegalStateException("Should not happen", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Should not happen", e);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package org.springframework.ui.binding.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.ui.binding.support.GenericBinder.BindingContext;
|
||||
|
||||
public class ListElementBinding extends AbstractBinding {
|
||||
|
||||
private List list;
|
||||
|
||||
private int index;
|
||||
|
||||
private Class<?> elementType;
|
||||
|
||||
private BindingContext bindingContext;
|
||||
|
||||
public ListElementBinding(int index, Class<?> elementType, List list, BindingContext bindingContext) {
|
||||
super(bindingContext);
|
||||
this.index = index;
|
||||
this.elementType = elementType;
|
||||
this.list = list;
|
||||
this.bindingContext = bindingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueModel getValueModel() {
|
||||
return new ValueModel() {
|
||||
public Object getValue() {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public Class<?> getValueType() {
|
||||
if (elementType != null) {
|
||||
return elementType;
|
||||
} else {
|
||||
return getValue().getClass();
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDescriptor<?> getValueTypeDescriptor() {
|
||||
return TypeDescriptor.valueOf(getValueType());
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
list.set(index, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
class ListElementValueModel implements ValueModel {
|
||||
|
||||
private List list;
|
||||
|
||||
private int index;
|
||||
|
||||
private Class<?> elementType;
|
||||
|
||||
public ListElementValueModel(int index, Class<?> elementType, List list) {
|
||||
this.index = index;
|
||||
this.elementType = elementType;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public Class<?> getValueType() {
|
||||
if (elementType != null) {
|
||||
return elementType;
|
||||
} else {
|
||||
return getValue().getClass();
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDescriptor<?> getValueTypeDescriptor() {
|
||||
return TypeDescriptor.valueOf(getValueType());
|
||||
}
|
||||
|
||||
public boolean isWriteable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
list.set(index, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
public class MapValueValueModel implements ValueModel {
|
||||
|
||||
private Object key;
|
||||
|
||||
private Class<?> elementType;
|
||||
|
||||
private Map map;
|
||||
|
||||
public MapValueValueModel(Object key, Class<?> elementType, Map map, BindingContext bindingContext) {
|
||||
this.key = key;
|
||||
this.elementType = elementType;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public Class<?> getValueType() {
|
||||
if (elementType != null) {
|
||||
return elementType;
|
||||
} else {
|
||||
return getValue().getClass();
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDescriptor<?> getValueTypeDescriptor() {
|
||||
return TypeDescriptor.valueOf(getValueType());
|
||||
}
|
||||
|
||||
public boolean isWriteable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package org.springframework.ui.binding.support;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.ui.binding.Binding;
|
||||
import org.springframework.ui.binding.support.GenericBinder.BindingContext;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
public class PropertyBinding extends AbstractBinding implements Binding {
|
||||
|
||||
private PropertyDescriptor property;
|
||||
|
||||
private Object object;
|
||||
|
||||
public PropertyBinding(PropertyDescriptor property, Object object, BindingContext bindingContext) {
|
||||
super(bindingContext);
|
||||
this.property = property;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
// Binding overrides
|
||||
|
||||
@Override
|
||||
public boolean isEditable() {
|
||||
return isWriteable() && super.isEditable();
|
||||
}
|
||||
|
||||
// implementing
|
||||
|
||||
protected ValueModel getValueModel() {
|
||||
return new ValueModel() {
|
||||
public Object getValue() {
|
||||
return ReflectionUtils.invokeMethod(property.getReadMethod(), object);
|
||||
}
|
||||
|
||||
public Class<?> getValueType() {
|
||||
return property.getPropertyType();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public TypeDescriptor<?> getValueTypeDescriptor() {
|
||||
return new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
ReflectionUtils.invokeMethod(property.getWriteMethod(), object, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private boolean isWriteable() {
|
||||
return property.getWriteMethod() != null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
public class PropertyNotFoundException extends RuntimeException {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
public class PropertyValueModel implements ValueModel {
|
||||
|
||||
private PropertyDescriptor property;
|
||||
|
||||
private Object object;
|
||||
|
||||
public PropertyValueModel(PropertyDescriptor property, Object object) {
|
||||
this.property = property;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return ReflectionUtils.invokeMethod(property.getReadMethod(), object);
|
||||
}
|
||||
|
||||
public Class<?> getValueType() {
|
||||
return property.getPropertyType();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public TypeDescriptor<?> getValueTypeDescriptor() {
|
||||
return new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
|
||||
}
|
||||
|
||||
public boolean isWriteable() {
|
||||
return property.getWriteMethod() != null;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
ReflectionUtils.invokeMethod(property.getWriteMethod(), object, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,20 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2004-2009 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.ui.binding.support;
|
||||
|
||||
import org.springframework.ui.binding.support.AbstractBinding.ValueModel;
|
||||
|
||||
class ValueBuffer {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package org.springframework.ui.binding.support;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
/**
|
||||
* For accessing the raw bound model object.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ValueModel {
|
||||
|
||||
/**
|
||||
* The model value.
|
||||
*/
|
||||
Object getValue();
|
||||
|
||||
/**
|
||||
* The model value type.
|
||||
*/
|
||||
Class<?> getValueType();
|
||||
|
||||
/**
|
||||
* The model value type descriptor.
|
||||
*/
|
||||
TypeDescriptor<?> getValueTypeDescriptor();
|
||||
|
||||
/**
|
||||
* If the model is writeable.
|
||||
*/
|
||||
boolean isWriteable();
|
||||
|
||||
/**
|
||||
* Set the model value.
|
||||
* @throws IllegalStateException if not writeable
|
||||
*/
|
||||
void setValue(Object value);
|
||||
}
|
||||
|
|
@ -20,9 +20,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.ui.alert.AlertContext;
|
||||
import org.springframework.ui.binding.Binder;
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
import org.springframework.ui.binding.BindingResults;
|
||||
import org.springframework.ui.binding.binder.Binder;
|
||||
import org.springframework.ui.binding.binder.BindingResult;
|
||||
import org.springframework.ui.binding.binder.BindingResults;
|
||||
import org.springframework.ui.validation.ValidationFailure;
|
||||
import org.springframework.ui.validation.Validator;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.springframework.ui.lifecycle;
|
||||
|
||||
import org.springframework.ui.binding.BindingResults;
|
||||
import org.springframework.ui.binding.binder.BindingResults;
|
||||
|
||||
/**
|
||||
* Decides if validation should run for an execution of the bind and validate lifecycle.
|
||||
|
|
|
|||
Loading…
Reference in New Issue