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.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.ui.binding.BindingResult;
|
|
||||||
import org.springframework.ui.binding.BindingResults;
|
|
||||||
|
|
||||||
class ArrayListBindingResults implements BindingResults {
|
class ArrayListBindingResults implements BindingResults {
|
||||||
|
|
||||||
|
|
@ -13,31 +13,25 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.ui.binding;
|
package org.springframework.ui.binding.binder;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.ui.binding.Binding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds user-entered values to properties of a model object.
|
* Binds user-entered values to properties of a model object.
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see #bind(String)
|
* @see #bind(String)
|
||||||
* @see #getBinding(String)
|
|
||||||
* @see #bind(Map)
|
* @see #bind(Map)
|
||||||
*/
|
*/
|
||||||
public interface Binder {
|
public interface Binder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model object for which property bindings may be accessed.
|
* The model this binder binds to.
|
||||||
*/
|
*/
|
||||||
Object getModel();
|
public 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the source values to the properties of the model.
|
* Bind the source values to the properties of the model.
|
||||||
|
|
@ -13,9 +13,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.alert.Alert;
|
||||||
|
import org.springframework.ui.binding.Binding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The result of a bind operation.
|
* The result of a bind operation.
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.ui.binding;
|
package org.springframework.ui.binding.binder;
|
||||||
|
|
||||||
import java.util.List;
|
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.Alert;
|
||||||
import org.springframework.ui.alert.Severity;
|
import org.springframework.ui.alert.Severity;
|
||||||
import org.springframework.ui.binding.BindingResult;
|
|
||||||
|
|
||||||
class BindingStatusResult implements 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.ui.binding;
|
package org.springframework.ui.binding.binder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.context.MessageSource;
|
||||||
import org.springframework.core.style.StylerUtils;
|
import org.springframework.core.style.StylerUtils;
|
||||||
import org.springframework.ui.alert.Alert;
|
import org.springframework.ui.alert.Alert;
|
||||||
import org.springframework.ui.alert.Severity;
|
import org.springframework.ui.alert.Severity;
|
||||||
import org.springframework.ui.binding.BindingResult;
|
|
||||||
import org.springframework.ui.message.MessageBuilder;
|
import org.springframework.ui.message.MessageBuilder;
|
||||||
import org.springframework.ui.message.ResolvableArgument;
|
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.context.MessageSource;
|
||||||
import org.springframework.core.style.StylerUtils;
|
import org.springframework.core.style.StylerUtils;
|
||||||
import org.springframework.ui.alert.Alert;
|
import org.springframework.ui.alert.Alert;
|
||||||
import org.springframework.ui.alert.Severity;
|
import org.springframework.ui.alert.Severity;
|
||||||
import org.springframework.ui.binding.BindingResult;
|
|
||||||
import org.springframework.ui.message.MessageBuilder;
|
import org.springframework.ui.message.MessageBuilder;
|
||||||
import org.springframework.ui.message.ResolvableArgument;
|
import org.springframework.ui.message.ResolvableArgument;
|
||||||
|
|
||||||
|
|
@ -13,11 +13,14 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.ui.binding.support;
|
package org.springframework.ui.binding.binder;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
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.
|
* A binder designed for use in HTTP (web) environments.
|
||||||
* Suited for binding user-provided HTTP query parameters to model properties.
|
* 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.
|
* Creates a new web binder for the model object.
|
||||||
* @param model the model object containing properties this binder will bind to
|
* @param model the model object containing properties this binder will bind to
|
||||||
*/
|
*/
|
||||||
public WebBinder(Object model) {
|
public WebBinder(BindingFactory bindingFactory) {
|
||||||
super(model);
|
super(bindingFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,7 +75,7 @@ public class WebBinder extends GenericBinder {
|
||||||
} else if (field.startsWith(presentPrefix)) {
|
} else if (field.startsWith(presentPrefix)) {
|
||||||
field = field.substring(presentPrefix.length());
|
field = field.substring(presentPrefix.length());
|
||||||
if (!sourceValues.containsKey(field) && !sourceValues.containsKey(defaultPrefix + field)) {
|
if (!sourceValues.containsKey(field) && !sourceValues.containsKey(defaultPrefix + field)) {
|
||||||
value = getEmptyValue((PropertyBinding) getBinding(field));
|
value = getEmptyValue(getBinding(field));
|
||||||
filteredValues.put(field, value);
|
filteredValues.put(field, value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -82,8 +85,8 @@ public class WebBinder extends GenericBinder {
|
||||||
return filteredValues;
|
return filteredValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getEmptyValue(PropertyBinding binding) {
|
protected Object getEmptyValue(Binding binding) {
|
||||||
Class<?> type = binding.getValueModel().getValueType();
|
Class<?> type = binding.getValueType();
|
||||||
if (boolean.class.equals(type) || Boolean.class.equals(type)) {
|
if (boolean.class.equals(type) || Boolean.class.equals(type)) {
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
} else {
|
} 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;
|
package org.springframework.ui.binding.config;
|
||||||
|
|
||||||
public interface Condition {
|
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;
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
import org.springframework.ui.binding.config.Condition;
|
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;
|
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;
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.springframework.ui.format.Formatter;
|
import org.springframework.ui.format.Formatter;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
// TODO should this delegate to type converter...
|
||||||
class DefaultFormatter implements Formatter {
|
class DefaultFormatter implements Formatter {
|
||||||
|
|
||||||
public static final Formatter INSTANCE = new DefaultFormatter();
|
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) {
|
public String format(Object object, Locale locale) {
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return "";
|
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;
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.lang.reflect.TypeVariable;
|
import java.lang.reflect.TypeVariable;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
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.Alert;
|
||||||
import org.springframework.ui.alert.Severity;
|
import org.springframework.ui.alert.Severity;
|
||||||
import org.springframework.ui.binding.Binding;
|
import org.springframework.ui.binding.Binding;
|
||||||
import org.springframework.ui.binding.support.GenericBinder.BindingContext;
|
|
||||||
import org.springframework.ui.format.Formatter;
|
import org.springframework.ui.format.Formatter;
|
||||||
import org.springframework.ui.message.MessageBuilder;
|
import org.springframework.ui.message.MessageBuilder;
|
||||||
import org.springframework.ui.message.ResolvableArgument;
|
import org.springframework.ui.message.ResolvableArgument;
|
||||||
|
|
||||||
public abstract class AbstractBinding implements Binding {
|
public class GenericBinding implements Binding {
|
||||||
|
|
||||||
|
private ValueModel valueModel;
|
||||||
|
|
||||||
private BindingContext bindingContext;
|
private BindingContext bindingContext;
|
||||||
|
|
||||||
|
|
@ -36,9 +53,10 @@ public abstract class AbstractBinding implements Binding {
|
||||||
|
|
||||||
private Exception invalidSourceValueCause;
|
private Exception invalidSourceValueCause;
|
||||||
|
|
||||||
public AbstractBinding(BindingContext bindingContext) {
|
public GenericBinding(ValueModel valueModel, BindingContext bindingContext) {
|
||||||
|
this.valueModel = valueModel;
|
||||||
this.bindingContext = bindingContext;
|
this.bindingContext = bindingContext;
|
||||||
buffer = new ValueBuffer(getValueModel());
|
buffer = new ValueBuffer(valueModel);
|
||||||
status = BindingStatus.CLEAN;
|
status = BindingStatus.CLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,16 +70,16 @@ public abstract class AbstractBinding implements Binding {
|
||||||
if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) {
|
if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) {
|
||||||
return buffer.getValue();
|
return buffer.getValue();
|
||||||
} else {
|
} else {
|
||||||
return getValueModel().getValue();
|
return valueModel.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getValueType() {
|
public Class<?> getValueType() {
|
||||||
return getValueModel().getValueType();
|
return valueModel.getValueType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEditable() {
|
public boolean isEditable() {
|
||||||
return bindingContext.getEditableCondition().isTrue();
|
return valueModel.isWriteable() && bindingContext.getEditableCondition().isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
|
|
@ -91,17 +109,20 @@ public abstract class AbstractBinding implements Binding {
|
||||||
status = BindingStatus.INVALID_SOURCE_VALUE;
|
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||||
}
|
}
|
||||||
} else if (sourceValue instanceof String[]) {
|
} else if (sourceValue instanceof String[]) {
|
||||||
|
Object parsed;
|
||||||
|
if (isMap()) {
|
||||||
String[] sourceValues = (String[]) sourceValue;
|
String[] sourceValues = (String[]) sourceValue;
|
||||||
Class<?> parsedType = getFormattedObjectType(bindingContext.getElementFormatter().getClass());
|
Formatter keyFormatter = bindingContext.getKeyFormatter();
|
||||||
if (parsedType == null) {
|
Formatter valueFormatter = bindingContext.getElementFormatter();
|
||||||
parsedType = String.class;
|
Map map = new LinkedHashMap(sourceValues.length);
|
||||||
}
|
|
||||||
Object parsed = Array.newInstance(parsedType, sourceValues.length);
|
|
||||||
for (int i = 0; i < sourceValues.length; i++) {
|
for (int i = 0; i < sourceValues.length; i++) {
|
||||||
|
String entryString = sourceValues[i];
|
||||||
Object parsedValue;
|
Object parsedValue;
|
||||||
try {
|
try {
|
||||||
parsedValue = bindingContext.getElementFormatter().parse(sourceValues[i], getLocale());
|
String[] keyValue = entryString.split("=");
|
||||||
Array.set(parsed, i, parsedValue);
|
Object parsedMapKey = keyFormatter.parse(keyValue[0], getLocale());
|
||||||
|
Object parsedMapValue = valueFormatter.parse(keyValue[1], getLocale());
|
||||||
|
map.put(parsedMapKey, parsedMapValue);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
this.sourceValue = sourceValue;
|
this.sourceValue = sourceValue;
|
||||||
invalidSourceValueCause = e;
|
invalidSourceValueCause = e;
|
||||||
|
|
@ -109,6 +130,24 @@ public abstract class AbstractBinding implements Binding {
|
||||||
break;
|
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) {
|
if (status != BindingStatus.INVALID_SOURCE_VALUE) {
|
||||||
try {
|
try {
|
||||||
buffer.setValue(coerseToValueType(parsed));
|
buffer.setValue(coerseToValueType(parsed));
|
||||||
|
|
@ -256,6 +295,13 @@ public abstract class AbstractBinding implements Binding {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Binding getMapValueBinding(Object key) {
|
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);
|
return bindingContext.getMapValueBinding(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,31 +309,25 @@ public abstract class AbstractBinding implements Binding {
|
||||||
public String formatValue(Object value) {
|
public String formatValue(Object value) {
|
||||||
Formatter formatter;
|
Formatter formatter;
|
||||||
if (Collection.class.isAssignableFrom(getValueType()) || getValueType().isArray() || isMap()) {
|
if (Collection.class.isAssignableFrom(getValueType()) || getValueType().isArray() || isMap()) {
|
||||||
formatter = getBindingContext().getElementFormatter();
|
formatter = bindingContext.getElementFormatter();
|
||||||
} else {
|
} else {
|
||||||
formatter = getBindingContext().getFormatter();
|
formatter = bindingContext.getFormatter();
|
||||||
}
|
}
|
||||||
return format(value, formatter);
|
return format(value, formatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// subclassing hooks
|
// internal helpers
|
||||||
|
|
||||||
protected BindingContext getBindingContext() {
|
private String format(Object value, Formatter formatter) {
|
||||||
return bindingContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract ValueModel getValueModel();
|
|
||||||
|
|
||||||
protected Locale getLocale() {
|
|
||||||
return LocaleContextHolder.getLocale();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String format(Object value, Formatter formatter) {
|
|
||||||
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
||||||
value = bindingContext.getTypeConverter().convert(value, formattedType);
|
value = bindingContext.getTypeConverter().convert(value, formattedType);
|
||||||
return formatter.format(value, getLocale());
|
return formatter.format(value, getLocale());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Locale getLocale() {
|
||||||
|
return LocaleContextHolder.getLocale();
|
||||||
|
}
|
||||||
|
|
||||||
private Class getFormattedObjectType(Class formatterClass) {
|
private Class getFormattedObjectType(Class formatterClass) {
|
||||||
Class classToIntrospect = formatterClass;
|
Class classToIntrospect = formatterClass;
|
||||||
while (classToIntrospect != null) {
|
while (classToIntrospect != null) {
|
||||||
|
|
@ -317,7 +357,7 @@ public abstract class AbstractBinding implements Binding {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object coerseToValueType(Object parsed) {
|
private Object coerseToValueType(Object parsed) {
|
||||||
TypeDescriptor targetType = getValueModel().getValueTypeDescriptor();
|
TypeDescriptor targetType = valueModel.getValueTypeDescriptor();
|
||||||
TypeConverter converter = bindingContext.getTypeConverter();
|
TypeConverter converter = bindingContext.getTypeConverter();
|
||||||
if (parsed != null && converter.canConvert(parsed.getClass(), targetType)) {
|
if (parsed != null && converter.canConvert(parsed.getClass(), targetType)) {
|
||||||
return converter.convert(parsed, targetType);
|
return converter.convert(parsed, targetType);
|
||||||
|
|
@ -338,39 +378,10 @@ public abstract class AbstractBinding implements Binding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal helpers
|
|
||||||
|
|
||||||
static abstract class AbstractAlert implements Alert {
|
static abstract class AbstractAlert implements Alert {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getCode() + " - " + getMessage();
|
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.beans.PropertyDescriptor;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.codehaus.groovy.binding.PropertyBinding;
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
import org.springframework.core.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.convert.TypeConverter;
|
import org.springframework.core.convert.TypeConverter;
|
||||||
import org.springframework.core.convert.support.DefaultTypeConverter;
|
import org.springframework.core.convert.support.DefaultTypeConverter;
|
||||||
import org.springframework.ui.binding.Binder;
|
|
||||||
import org.springframework.ui.binding.Binding;
|
import org.springframework.ui.binding.Binding;
|
||||||
import org.springframework.ui.binding.BindingResult;
|
import org.springframework.ui.binding.BindingFactory;
|
||||||
import org.springframework.ui.binding.BindingResults;
|
import org.springframework.ui.binding.binder.Binder;
|
||||||
import org.springframework.ui.binding.MissingSourceValuesException;
|
import org.springframework.ui.binding.binder.BindingResult;
|
||||||
import org.springframework.ui.binding.Binding.BindingStatus;
|
|
||||||
import org.springframework.ui.binding.config.BindingRuleConfiguration;
|
import org.springframework.ui.binding.config.BindingRuleConfiguration;
|
||||||
import org.springframework.ui.binding.config.Condition;
|
import org.springframework.ui.binding.config.Condition;
|
||||||
import org.springframework.ui.format.Formatter;
|
import org.springframework.ui.format.Formatter;
|
||||||
|
|
@ -47,7 +47,7 @@ import org.springframework.util.Assert;
|
||||||
* @see #setTypeConverter(TypeConverter)
|
* @see #setTypeConverter(TypeConverter)
|
||||||
* @see #bind(Map)
|
* @see #bind(Map)
|
||||||
*/
|
*/
|
||||||
public class GenericBinder implements Binder {
|
public class GenericBindingFactory implements BindingFactory {
|
||||||
|
|
||||||
private Object model;
|
private Object model;
|
||||||
|
|
||||||
|
|
@ -59,13 +59,11 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
private MessageSource messageSource;
|
private MessageSource messageSource;
|
||||||
|
|
||||||
private String[] requiredProperties = new String[0];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new binder for the model object.
|
* Creates a new binder for the model object.
|
||||||
* @param model the model object containing properties this binder will bind to
|
* @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");
|
Assert.notNull(model, "The model to bind to is required");
|
||||||
this.model = model;
|
this.model = model;
|
||||||
bindingRules = new HashMap<String, GenericBindingRule>();
|
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
|
* @param propertyPath binding rule property path in format prop.nestedProp
|
||||||
* @return
|
* @return a builder for the binding rule
|
||||||
*/
|
*/
|
||||||
public BindingRuleConfiguration bindingRule(String propertyPath) {
|
public BindingRuleConfiguration bindingRule(String propertyPath) {
|
||||||
PropertyPath path = new PropertyPath(propertyPath);
|
PropertyPath path = new PropertyPath(propertyPath);
|
||||||
|
|
@ -142,55 +140,6 @@ public class GenericBinder implements Binder {
|
||||||
return binding;
|
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) {
|
private GenericBindingRule getBindingRule(String property) {
|
||||||
GenericBindingRule rule = bindingRules.get(property);
|
GenericBindingRule rule = bindingRules.get(property);
|
||||||
if (rule == null) {
|
if (rule == null) {
|
||||||
|
|
@ -200,20 +149,6 @@ public class GenericBinder implements Binder {
|
||||||
return rule;
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
class GenericBindingRule implements BindingRuleConfiguration, BindingContext {
|
class GenericBindingRule implements BindingRuleConfiguration, BindingContext {
|
||||||
|
|
||||||
|
|
@ -223,10 +158,10 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
private Formatter formatter;
|
private Formatter formatter;
|
||||||
|
|
||||||
private Formatter elementFormatter;
|
|
||||||
|
|
||||||
private Formatter keyFormatter;
|
private Formatter keyFormatter;
|
||||||
|
|
||||||
|
private Formatter elementFormatter;
|
||||||
|
|
||||||
private Condition editableCondition = Condition.ALWAYS_TRUE;
|
private Condition editableCondition = Condition.ALWAYS_TRUE;
|
||||||
|
|
||||||
private Condition enabledCondition = 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<Integer, Binding> listElementBindings;
|
||||||
|
|
||||||
|
private Map<Object, Binding> mapValueBindings;
|
||||||
|
|
||||||
public GenericBindingRule(String property, Class modelClass) {
|
public GenericBindingRule(String property, Class modelClass) {
|
||||||
this.modelClass = modelClass;
|
this.modelClass = modelClass;
|
||||||
this.property = findPropertyDescriptor(property);
|
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() {
|
public Formatter<?> getKeyFormatter() {
|
||||||
if (keyFormatter != null) {
|
if (keyFormatter != null) {
|
||||||
return keyFormatter;
|
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() {
|
public Condition getEnabledCondition() {
|
||||||
return enabledCondition;
|
return enabledCondition;
|
||||||
}
|
}
|
||||||
|
|
@ -295,79 +232,34 @@ public class GenericBinder implements Binder {
|
||||||
return getBindingRule(property, binding.getValueType()).getBinding(binding.getValue());
|
return getBindingRule(property, binding.getValueType()).getBinding(binding.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Binding getListElementBinding(final int index) {
|
public Binding getListElementBinding(int index) {
|
||||||
if (listElementBindings == null) {
|
if (listElementBindings == null) {
|
||||||
listElementBindings = new HashMap<Integer, Binding>();
|
listElementBindings = new HashMap<Integer, Binding>();
|
||||||
}
|
}
|
||||||
growListIfNecessary(index);
|
growListIfNecessary(index);
|
||||||
Binding binding = listElementBindings.get(index);
|
Binding binding = listElementBindings.get(index);
|
||||||
if (binding == null) {
|
if (binding == null) {
|
||||||
final Map<String, Binding> nestedBindings = new HashMap<String, Binding>();
|
BindingContext bindingContext = new ListElementBindingContext(index, this);
|
||||||
BindingContext listContext = new BindingContext() {
|
ValueModel valueModel = new ListElementValueModel(index, getElementType(), (List) this.binding.getValue());
|
||||||
public MessageSource getMessageSource() {
|
binding = new GenericBinding(valueModel, bindingContext);
|
||||||
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);
|
|
||||||
listElementBindings.put(index, binding);
|
listElementBindings.put(index, binding);
|
||||||
}
|
}
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Binding getMapValueBinding(Object key) {
|
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() {
|
public String getLabel() {
|
||||||
|
|
@ -416,8 +308,12 @@ public class GenericBinder implements Binder {
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
private Class<?> getElementType() {
|
private Class<?> getElementType() {
|
||||||
|
if (Map.class.isAssignableFrom(property.getPropertyType())) {
|
||||||
|
return GenericCollectionTypeResolver.getMapValueReturnType(property.getReadMethod());
|
||||||
|
} else {
|
||||||
return GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
|
return GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Class<?> getKeyType() {
|
private Class<?> getKeyType() {
|
||||||
return GenericCollectionTypeResolver.getMapKeyReturnType(property.getReadMethod());
|
return GenericCollectionTypeResolver.getMapKeyReturnType(property.getReadMethod());
|
||||||
|
|
@ -443,7 +339,8 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
Binding getBinding(Object model) {
|
Binding getBinding(Object model) {
|
||||||
if (binding == null) {
|
if (binding == null) {
|
||||||
binding = new PropertyBinding(property, model, this);
|
PropertyValueModel valueModel = new PropertyValueModel(property, model);
|
||||||
|
binding = new GenericBinding(valueModel, this);
|
||||||
}
|
}
|
||||||
return binding;
|
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) {
|
private void growListIfNecessary(int index) {
|
||||||
List list = (List) binding.getValue();
|
List list = (List) binding.getValue();
|
||||||
if (list == null) {
|
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) {
|
private List newListValue(Class<?> type) {
|
||||||
if (type.isInterface()) {
|
if (type.isInterface()) {
|
||||||
return (List) newValue(ArrayList.class);
|
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();
|
final Map<String, Binding> nestedBindings = new HashMap<String, Binding>();
|
||||||
|
|
||||||
Condition getEnabledCondition();
|
|
||||||
|
|
||||||
Condition getVisibleCondition();
|
|
||||||
|
|
||||||
Binding getBinding(String property);
|
|
||||||
|
|
||||||
Formatter getFormatter();
|
|
||||||
|
|
||||||
Formatter getElementFormatter();
|
|
||||||
|
|
||||||
Formatter getKeyFormatter();
|
|
||||||
|
|
||||||
Binding getListElementBinding(int index);
|
|
||||||
|
|
||||||
Binding getMapValueBinding(Object key);
|
|
||||||
|
|
||||||
String getLabel();
|
|
||||||
|
|
||||||
|
public ListElementBindingContext(int index, GenericBindingRule listBindingContext) {
|
||||||
|
this.index = index;
|
||||||
|
this.listBindingContext = listBindingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRequired(String[] propertyPaths) {
|
public MessageSource getMessageSource() {
|
||||||
this.requiredProperties = propertyPaths;
|
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.beans.PropertyDescriptor;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.lang.reflect.TypeVariable;
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
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.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.AnnotationFormatterFactory;
|
||||||
import org.springframework.ui.format.Formatted;
|
import org.springframework.ui.format.Formatted;
|
||||||
import org.springframework.ui.format.Formatter;
|
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.
|
* 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 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) {
|
public Formatter<?> getFormatter(PropertyDescriptor property) {
|
||||||
|
Assert.notNull(property, "The PropertyDescriptor is required");
|
||||||
TypeDescriptor<?> propertyType = new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
|
TypeDescriptor<?> propertyType = new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
|
||||||
Annotation[] annotations = propertyType.getAnnotations();
|
Annotation[] annotations = propertyType.getAnnotations();
|
||||||
for (Annotation a : annotations) {
|
for (Annotation a : annotations) {
|
||||||
|
|
@ -60,11 +78,13 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
||||||
Formatter<?> formatter = null;
|
Formatter<?> formatter = null;
|
||||||
Class<?> type;
|
Class<?> type;
|
||||||
if (propertyType.isCollection() || propertyType.isArray()) {
|
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) {
|
if (formatter != null) {
|
||||||
return formatter;
|
return formatter;
|
||||||
} else {
|
} else {
|
||||||
return DefaultFormatter.COLLECTION_FORMATTER;
|
return new DefaultCollectionFormatter(collectionType, this);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = propertyType.getType();
|
type = propertyType.getType();
|
||||||
|
|
@ -73,6 +93,7 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Formatter<?> getFormatter(Class<?> type) {
|
public Formatter<?> getFormatter(Class<?> type) {
|
||||||
|
Assert.notNull(type, "The Class of the object to format is required");
|
||||||
Formatter formatter = typeFormatters.get(type);
|
Formatter formatter = typeFormatters.get(type);
|
||||||
if (formatter != null) {
|
if (formatter != null) {
|
||||||
return formatter;
|
return formatter;
|
||||||
|
|
@ -83,20 +104,20 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
||||||
try {
|
try {
|
||||||
formatter = (Formatter) formatterClass.newInstance();
|
formatter = (Formatter) formatterClass.newInstance();
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
// TODO better runtime exception
|
throw new IllegalStateException(
|
||||||
throw new IllegalStateException(e);
|
"Formatter referenced by @Formatted annotation does not have default constructor", e);
|
||||||
} catch (IllegalAccessException 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);
|
typeFormatters.put(type, formatter);
|
||||||
return formatter;
|
return formatter;
|
||||||
} else {
|
} else {
|
||||||
return DefaultFormatter.INSTANCE;
|
return new DefaultFormatter(type, typeConverter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void add(Class<?> propertyType, Formatter<?> formatter) {
|
public void add(Class<?> propertyType, Formatter<?> formatter) {
|
||||||
if (propertyType.isAnnotation()) {
|
if (propertyType.isAnnotation()) {
|
||||||
annotationFormatters.put(propertyType, new SimpleAnnotationFormatterFactory(formatter));
|
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;
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
public class PropertyNotFoundException extends RuntimeException {
|
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;
|
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;
|
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;
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
import org.springframework.ui.binding.support.AbstractBinding.ValueModel;
|
|
||||||
|
|
||||||
class ValueBuffer {
|
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 java.util.Map;
|
||||||
|
|
||||||
import org.springframework.ui.alert.AlertContext;
|
import org.springframework.ui.alert.AlertContext;
|
||||||
import org.springframework.ui.binding.Binder;
|
import org.springframework.ui.binding.binder.Binder;
|
||||||
import org.springframework.ui.binding.BindingResult;
|
import org.springframework.ui.binding.binder.BindingResult;
|
||||||
import org.springframework.ui.binding.BindingResults;
|
import org.springframework.ui.binding.binder.BindingResults;
|
||||||
import org.springframework.ui.validation.ValidationFailure;
|
import org.springframework.ui.validation.ValidationFailure;
|
||||||
import org.springframework.ui.validation.Validator;
|
import org.springframework.ui.validation.Validator;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.ui.lifecycle;
|
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.
|
* Decides if validation should run for an execution of the bind and validate lifecycle.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue