Created
July 9, 2012 06:35
-
-
Save ndeverge/3074629 to your computer and use it in GitHub Desktop.
Play! Form patch (see http://stackoverflow.com/questions/11388269/playframework-illegalstateexception-after-form-validation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package patch; | |
import static play.libs.F.None; | |
import static play.libs.F.Some; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import org.springframework.beans.MutablePropertyValues; | |
import org.springframework.validation.BindingResult; | |
import org.springframework.validation.DataBinder; | |
import org.springframework.validation.FieldError; | |
import org.springframework.validation.beanvalidation.SpringValidatorAdapter; | |
import play.data.Form; | |
import play.data.validation.ValidationError; | |
import play.libs.F.Option; | |
/** | |
* This class is a patched version of a Play bug.<br> | |
* The bug happens when you submit a form with errors and you want to prefill | |
* the already entered data. | |
* | |
* @author ndeverge | |
* | |
* @param <T> | |
*/ | |
public class PatchedForm<T> extends Form<T> { | |
private final String rootName; | |
private final Class<T> backedType; | |
private final Map<String, List<ValidationError>> errors; | |
public PatchedForm(final Class<T> clazz) { | |
this(null, clazz); | |
} | |
@SuppressWarnings("unchecked") | |
public PatchedForm(final String name, final Class<T> clazz) { | |
this(name, clazz, new HashMap<String, String>(), | |
new HashMap<String, List<ValidationError>>(), None()); | |
} | |
/** | |
* Creates a new <code>Form</code>. | |
* | |
* @param clazz | |
* wrapped class | |
* @param data | |
* the current form data (used to display the form) | |
* @param errors | |
* the collection of errors associated with this form | |
* @param value | |
* optional concrete value of type <code>T</code> if the form | |
* submission was successful | |
*/ | |
public PatchedForm(final String rootName, final Class<T> clazz, | |
final Map<String, String> data, | |
final Map<String, List<ValidationError>> errors, | |
final Option<T> value) { | |
super(rootName, clazz, data, errors, value); | |
this.rootName = rootName; | |
this.backedType = clazz; | |
this.errors = errors; | |
} | |
private T blankInstance() { | |
try { | |
return backedType.newInstance(); | |
} catch (Exception e) { | |
throw new RuntimeException("Cannot instantiate " + backedType | |
+ ". It must have a default constructor", e); | |
} | |
} | |
@SuppressWarnings({ "unchecked", "rawtypes" }) | |
@Override | |
public Form<T> bind(final Map<String, String> data, | |
final String... allowedFields) { | |
DataBinder dataBinder = null; | |
Map<String, String> objectData = data; | |
if (rootName == null) { | |
dataBinder = new DataBinder(blankInstance()); | |
} else { | |
dataBinder = new DataBinder(blankInstance(), rootName); | |
objectData = new HashMap<String, String>(); | |
for (String key : data.keySet()) { | |
if (key.startsWith(rootName + ".")) { | |
objectData.put(key.substring(rootName.length() + 1), | |
data.get(key)); | |
} | |
} | |
} | |
if (allowedFields.length > 0) { | |
dataBinder.setAllowedFields(allowedFields); | |
} | |
dataBinder.setValidator(new SpringValidatorAdapter( | |
play.data.validation.Validation.getValidator())); | |
dataBinder.setConversionService(play.data.format.Formatters.conversion); | |
dataBinder.setAutoGrowNestedPaths(true); | |
dataBinder.bind(new MutablePropertyValues(objectData)); | |
dataBinder.validate(); | |
BindingResult result = dataBinder.getBindingResult(); | |
if (result.hasErrors()) { | |
Map<String, List<ValidationError>> errors = new HashMap<String, List<ValidationError>>(); | |
for (FieldError error : result.getFieldErrors()) { | |
String key = error.getObjectName() + "." + error.getField(); | |
if (key.startsWith("target.") && rootName == null) { | |
key = key.substring(7); | |
} | |
List<Object> arguments = new ArrayList<Object>(); | |
for (Object arg : error.getArguments()) { | |
if (!(arg instanceof org.springframework.context.support.DefaultMessageSourceResolvable)) { | |
arguments.add(arg); | |
} | |
} | |
if (!errors.containsKey(key)) { | |
errors.put(key, new ArrayList<ValidationError>()); | |
} | |
errors.get(key) | |
.add(new ValidationError(key, | |
error.isBindingFailure() ? "error.invalid" | |
: error.getDefaultMessage(), arguments)); | |
} | |
return new Form(rootName, backedType, data, errors, None()); | |
} else { | |
Object globalError = null; | |
if (result.getTarget() != null) { | |
try { | |
java.lang.reflect.Method v = result.getTarget().getClass() | |
.getMethod("validate"); | |
globalError = v.invoke(result.getTarget()); | |
} catch (NoSuchMethodException e) { | |
} catch (Throwable e) { | |
throw new RuntimeException(e); | |
} | |
} | |
if (globalError != null) { | |
Map<String, List<ValidationError>> errors = new HashMap<String, List<ValidationError>>(); | |
if (globalError instanceof String) { | |
errors.put("", new ArrayList<ValidationError>()); | |
errors.get("").add( | |
new ValidationError("", (String) globalError, | |
new ArrayList())); | |
} else if (globalError instanceof List) { | |
errors.put("", (List<ValidationError>) globalError); | |
} else if (globalError instanceof Map) { | |
errors = (Map<String, List<ValidationError>>) globalError; | |
} | |
// Here is the patch !! | |
if (result.getTarget() != null) { | |
return new Form(rootName, backedType, data, errors, | |
Some((T) result.getTarget())); | |
} else { | |
return new Form(rootName, backedType, data, errors, None()); | |
} | |
} | |
return new Form(rootName, backedType, new HashMap<String, String>( | |
data), new HashMap<String, List<ValidationError>>(errors), | |
Some((T) result.getTarget())); | |
} | |
} | |
} |
i figured it out. Thanks for the patch.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hi. am new in play framework and have the problem with which this patch can resolve , my question is how do I apply the patch ?