|
|
|
@ -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; |
|
|
|
package org.springframework.ui.lifecycle; |
|
|
|
|
|
|
|
|
|
|
|
import java.util.Map; |
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
|
|
@ -23,14 +23,18 @@ import org.springframework.ui.binding.UserValues; |
|
|
|
import org.springframework.ui.binding.support.WebBinder; |
|
|
|
import org.springframework.ui.binding.support.WebBinder; |
|
|
|
import org.springframework.ui.message.MessageBuilder; |
|
|
|
import org.springframework.ui.message.MessageBuilder; |
|
|
|
import org.springframework.ui.message.MessageContext; |
|
|
|
import org.springframework.ui.message.MessageContext; |
|
|
|
import org.springframework.ui.validation.ValidationResults; |
|
|
|
import org.springframework.ui.message.MessageResolver; |
|
|
|
import org.springframework.ui.validation.Validator; |
|
|
|
import org.springframework.ui.validation.Validator; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Implementation of the bind and validate lifecycle for web (HTTP) environments. |
|
|
|
|
|
|
|
* @author Keith Donald |
|
|
|
|
|
|
|
* @since 3.0 |
|
|
|
|
|
|
|
*/ |
|
|
|
public class WebBindAndValidateLifecycle { |
|
|
|
public class WebBindAndValidateLifecycle { |
|
|
|
|
|
|
|
|
|
|
|
private final WebBinder binder; |
|
|
|
private final WebBinder binder; |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unused") |
|
|
|
|
|
|
|
private final MessageContext messageContext; |
|
|
|
private final MessageContext messageContext; |
|
|
|
|
|
|
|
|
|
|
|
private ValidationDecider validationDecider = ValidationDecider.ALWAYS_VALIDATE; |
|
|
|
private ValidationDecider validationDecider = ValidationDecider.ALWAYS_VALIDATE; |
|
|
|
@ -38,6 +42,9 @@ public class WebBindAndValidateLifecycle { |
|
|
|
private Validator validator; |
|
|
|
private Validator validator; |
|
|
|
|
|
|
|
|
|
|
|
public WebBindAndValidateLifecycle(Object model, MessageContext messageContext) { |
|
|
|
public WebBindAndValidateLifecycle(Object model, MessageContext messageContext) { |
|
|
|
|
|
|
|
// TODO allow binder to be configured with bindings from model metadata
|
|
|
|
|
|
|
|
// TODO support @Bound property annotation?
|
|
|
|
|
|
|
|
// TODO support @StrictBinding class-level annotation?
|
|
|
|
this.binder = new WebBinder(model); |
|
|
|
this.binder = new WebBinder(model); |
|
|
|
this.messageContext = messageContext; |
|
|
|
this.messageContext = messageContext; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -46,29 +53,24 @@ public class WebBindAndValidateLifecycle { |
|
|
|
UserValues values = binder.createUserValues(userMap); |
|
|
|
UserValues values = binder.createUserValues(userMap); |
|
|
|
BindingResults bindingResults = binder.bind(values); |
|
|
|
BindingResults bindingResults = binder.bind(values); |
|
|
|
if (validationDecider.shouldValidateAfter(bindingResults)) { |
|
|
|
if (validationDecider.shouldValidateAfter(bindingResults)) { |
|
|
|
ValidationResults validationResults = validator.validate(binder.getModel(), bindingResults.successes() |
|
|
|
// TODO get validation results
|
|
|
|
.properties()); |
|
|
|
validator.validate(binder.getModel(), bindingResults.successes().properties()); |
|
|
|
} |
|
|
|
} |
|
|
|
// TODO translate binding and validation results into messages
|
|
|
|
|
|
|
|
MessageBuilder builder = new MessageBuilder(); |
|
|
|
MessageBuilder builder = new MessageBuilder(); |
|
|
|
for (BindingResult result : bindingResults.failures()) { |
|
|
|
for (BindingResult result : bindingResults.failures()) { |
|
|
|
builder. |
|
|
|
MessageResolver message = builder.code(modelPropertyError(result)).code(propertyError(result)).code( |
|
|
|
code(modelPropertyError(result)). |
|
|
|
typeError(result)).code(error(result)).resolvableArg("label", getModelProperty(result)).arg( |
|
|
|
code(propertyError(result)). |
|
|
|
"value", result.getUserValue()). |
|
|
|
code(typeError(result)). |
|
|
|
// TODO add binding el resolver allowing binding.format to be called
|
|
|
|
code(error(result)). |
|
|
|
arg("binding", binder.getBinding(result.getProperty())). |
|
|
|
//argContextFactory(createContextFactory(bindingResult)).
|
|
|
|
// TODO allow binding result to contribute additional arguments
|
|
|
|
// TODO arg names
|
|
|
|
build(); |
|
|
|
// TODO el support including ability to setup evaluation context
|
|
|
|
// TODO should model name be part of element id?
|
|
|
|
//resolvableArg("label", getModelProperty(result)).
|
|
|
|
messageContext.add(message, result.getProperty()); |
|
|
|
//arg("value", result.getUserValue()).
|
|
|
|
|
|
|
|
//arg("binding", binder.getBinding(result.getProperty())).
|
|
|
|
|
|
|
|
//args(result.getErrorArguments()).
|
|
|
|
|
|
|
|
build(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
// TODO expose property Binding in EL context for property error message resolution?
|
|
|
|
// TODO translate validation results into messages
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String modelPropertyError(BindingResult result) { |
|
|
|
private String modelPropertyError(BindingResult result) { |
|
|
|
return getModelProperty(result) + "." + result.getErrorCode(); |
|
|
|
return getModelProperty(result) + "." + result.getErrorCode(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -77,20 +79,21 @@ public class WebBindAndValidateLifecycle { |
|
|
|
return result.getProperty() + "." + result.getErrorCode(); |
|
|
|
return result.getProperty() + "." + result.getErrorCode(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String typeError(BindingResult result) { |
|
|
|
private String typeError(BindingResult result) { |
|
|
|
return binder.getBinding(result.getProperty()).getType().getName() + "." + result.getErrorCode(); |
|
|
|
return binder.getBinding(result.getProperty()).getType().getName() + "." + result.getErrorCode(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String error(BindingResult result) { |
|
|
|
private String error(BindingResult result) { |
|
|
|
return result.getErrorCode(); |
|
|
|
return result.getErrorCode(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String getModelProperty(BindingResult result) { |
|
|
|
private String getModelProperty(BindingResult result) { |
|
|
|
return getModel() + "." + result.getProperty(); |
|
|
|
return getModel() + "." + result.getProperty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String getModel() { |
|
|
|
private String getModel() { |
|
|
|
// TODO would be nice if model name was module.ClassName by default where module is subpackage of app base package
|
|
|
|
// TODO would be nice if model name was module.ClassName by default where module is subpackage of app base package
|
|
|
|
|
|
|
|
// TODO model name should probably be specifiable using class-level annotation
|
|
|
|
return binder.getModel().getClass().getName(); |
|
|
|
return binder.getModel().getClass().getName(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|