From 88a68042baff94f0d5083180d5386545b616331f Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Mon, 27 Jul 2009 01:05:46 +0000 Subject: [PATCH] Initial import of GenericBinder. --- .../model/binder/support/GenericBinder.java | 148 ++++++++++++++++++ .../binder/support/GenericBinderTests.java | 148 ++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java create mode 100644 org.springframework.context/src/test/java/org/springframework/model/binder/support/GenericBinderTests.java diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java new file mode 100644 index 0000000000..f81b1c36b5 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java @@ -0,0 +1,148 @@ +/* + * 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.model.binder.support; + +import java.util.Map; + +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParseException; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParserConfiguration; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.model.alert.Alert; +import org.springframework.model.alert.Severity; +import org.springframework.model.binder.Binder; +import org.springframework.model.binder.BindingResult; +import org.springframework.model.binder.BindingResults; + +/** + * A {@link Binder} implementation that accepts any target object and uses + * Spring's Expression Language support to evaluate the keys in the field + * value Map. + * + * @author Mark Fisher + * @since 3.0 + */ +public class GenericBinder extends AbstractBinder { + + private final ExpressionParser parser = new SpelExpressionParser( + SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull | + SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize); + + + @Override + public BindingResults bind(Map fieldValues, Object model) { + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + evaluationContext.setRootObject(model); + FieldBinder fieldBinder = new EvaluationContextFieldBinder(this.parser, evaluationContext); + return this.getBindTemplate().bind(fieldValues, fieldBinder); + } + + + private static class EvaluationContextFieldBinder implements FieldBinder { + + private final ExpressionParser parser; + + private final EvaluationContext context; + + private EvaluationContextFieldBinder(ExpressionParser parser, EvaluationContext context) { + this.parser = parser; + this.context = context; + } + + @Override + public BindingResult bind(String key, Object value) { + Alert alert = null; + try { + Expression e = this.parser.parseExpression(key); + e.setValue(this.context, value); + alert = new BindSuccessAlert(); + } + catch (ParseException e) { + alert = new ParseFailureAlert(e); + } + catch (EvaluationException e) { + alert = new EvaluationFailureAlert(e); + } + return new AlertBindingResult(key, value, alert); + } + } + + + private static class BindSuccessAlert implements Alert { + + public String getCode() { + return "bindSuccess"; + } + + public String getMessage() { + return "Binding successful"; + } + + public Severity getSeverity() { + return Severity.INFO; + } + } + + + private static class ParseFailureAlert implements Alert { + + private final ParseException exception; + + ParseFailureAlert(ParseException exception) { + this.exception = exception; + } + + public String getCode() { + return "parserFailed"; + } + + public String getMessage() { + return exception.getMessage(); + } + + public Severity getSeverity() { + return Severity.ERROR; + } + } + + + private static class EvaluationFailureAlert implements Alert { + + private final EvaluationException exception; + + EvaluationFailureAlert(EvaluationException exception) { + this.exception = exception; + } + + public String getCode() { + return "evaluationFailed"; + } + + public String getMessage() { + return exception.getMessage(); + } + + public Severity getSeverity() { + return Severity.ERROR; + } + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/model/binder/support/GenericBinderTests.java b/org.springframework.context/src/test/java/org/springframework/model/binder/support/GenericBinderTests.java new file mode 100644 index 0000000000..b17d4b927c --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/model/binder/support/GenericBinderTests.java @@ -0,0 +1,148 @@ +/* + * 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.model.binder.support; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.core.style.ToStringCreator; +import org.springframework.model.binder.Binder; + +/** + * @author Mark Fisher + * @since 3.0 + */ +public class GenericBinderTests { + + @Test + public void simpleValues() { + Person person = new Person(); + Map map = new HashMap(); + map.put("name", "John Doe"); + map.put("age", 42); + map.put("male", true); + Binder binder = new GenericBinder(); + binder.bind(map, person); + assertEquals("John Doe", person.name); + assertEquals(42, person.age); + assertTrue(person.male); + } + + @Test + public void nestedValues() { + Person person = new Person(); + Map map = new HashMap(); + map.put("pob.city", "Rome"); + map.put("pob.country", "Italy"); + Binder binder = new GenericBinder(); + binder.bind(map, person); + assertNotNull(person.pob); + assertEquals("Rome", person.pob.city); + assertEquals("Italy", person.pob.country); + } + + + public static class Person { + + private String name; + + private int age; + + private boolean male; + + private PlaceOfBirth pob; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public boolean isMale() { + return male; + } + + public void setMale(boolean male) { + this.male = male; + } + + public PlaceOfBirth getPob() { + return pob; + } + + public void setPob(PlaceOfBirth pob) { + this.pob = pob; + } + + public String toString() { + return new ToStringCreator(this) + .append("name", name) + .append("age", age) + .append("male", male) + .append("pob", pob) + .toString(); + } + } + + + public static class PlaceOfBirth { + + private String city; + + private String country; + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String toString() { + return new ToStringCreator(this) + .append("city", city) + .append("country", country) + .toString(); + } + } + +}