org.springframework.springfaces.mvc.bind.ReverseDataBinderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.springfaces.mvc.bind.ReverseDataBinderTest.java

Source

/*
 * Copyright 2010-2012 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.springfaces.mvc.bind;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.beans.PropertyEditorSupport;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.validation.DataBinder;

/**
 * Tests for {@link ReverseDataBinder}.
 * 
 * @author Phillip Webb
 */
public class ReverseDataBinderTest {

    Log logger = LogFactory.getLog(getClass());

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    private static final Date D01_12_2009;
    static {
        Calendar c = Calendar.getInstance();
        c.set(2009, Calendar.DECEMBER, 1, 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);
        D01_12_2009 = c.getTime();
    }

    private static final String S01_12_2009 = "2009/01/12";

    private FormattingConversionService conversionService;

    @Before
    public void setup() {
        this.conversionService = new FormattingConversionService();
        this.conversionService.addConverter(new CustomTypeToStringConverter());
        this.conversionService.addConverter(new StringToCustomTypeConverter());
    }

    /**
     * Setup the databinder with a customer date editor and a conversion service
     * @param dataBinder
     */
    private void initBinder(DataBinder dataBinder) {
        DateFormat df = new SimpleDateFormat("yyyy/dd/MM");
        df.setLenient(false);
        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));
        dataBinder.setConversionService(this.conversionService);
    }

    @Test
    public void shouldReverseConvertWithCustomEditor() throws Exception {
        doTestReverseConvert(S01_12_2009, D01_12_2009);
    }

    @Test
    public void shouldReverseConvertForDefaultType() throws Exception {
        doTestReverseConvert("1234", new Integer(1234));
    }

    @Test
    public void shouldReverseConvertWithNull() throws Exception {
        doTestReverseConvert(null, null);
    }

    private void doTestReverseConvert(String value, Object expected) throws Exception {
        DataBinder dataBinder = new DataBinder(null);
        initBinder(dataBinder);
        Object converted = (value == null ? null : dataBinder.convertIfNecessary(value, expected.getClass()));
        assertThat(converted, is(equalTo(expected)));
        ReverseDataBinder reverseDataBinder = new ReverseDataBinder(dataBinder);
        String reversed = reverseDataBinder.reverseConvert(converted);
        assertThat(reversed, is(equalTo(value)));
    }

    @Test
    public void shouldReverseBind() throws Exception {
        Sample target = new Sample();
        DataBinder dataBinder = new DataBinder(target);
        initBinder(dataBinder);
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.addPropertyValue("customTypeValue", "custom");
        pvs.addPropertyValue("dateValue", S01_12_2009);
        pvs.addPropertyValue("integerValue", "123");
        pvs.addPropertyValue("stringValue", "string");
        dataBinder.bind(pvs);

        assertThat(target.getIntegerValue(), is(equalTo(new Integer(123))));
        assertThat(target.getStringValue(), is(equalTo("string")));
        assertThat(target.getDateValue(), is(equalTo(D01_12_2009)));
        assertThat(target.getCustomTypeValue(), is(equalTo(new CustomType("custom"))));

        ReverseDataBinder reverseDataBinder = new ReverseDataBinder(dataBinder);
        PropertyValues result = reverseDataBinder.reverseBind();
        for (int i = 0; i < result.getPropertyValues().length; i++) {
            PropertyValue pv = result.getPropertyValues()[i];
            this.logger.info(pv.getName() + "=" + pv.getValue());
        }
        assertThat(result, is(equalTo((Object) pvs)));
    }

    @Test
    public void shouldFailReverseBindIfBindWillFail() throws Exception {
        Sample target = new Sample();
        DataBinder dataBinder = new DataBinder(target);
        dataBinder.setRequiredFields(new String[] { "integerValue" });
        ReverseDataBinder reverseDataBinder = new ReverseDataBinder(dataBinder);
        this.thrown.expect(IllegalStateException.class);
        this.thrown.expectMessage(
                "Unable to reverse bind from target 'target', the properties 'PropertyValues: length=0' will result in binding errors "
                        + "when re-bound [Field error in object 'target' on field 'integerValue': rejected value []; codes "
                        + "[required.target.integerValue,required.integerValue,required.java.lang.Integer,required]; arguments "
                        + "[org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.integerValue,integerValue]; "
                        + "arguments []; default message [integerValue]]; default message [Field 'integerValue' is required]]");
        reverseDataBinder.reverseBind();
    }

    @Test
    public void shouldReverseBindWithDefaultValues() throws Exception {
        doTestReverseBindWithDefaultValues(false, false);
    }

    @Test
    public void shouldReverseBindWithDefaultValuesNotSkipped() throws Exception {
        doTestReverseBindWithDefaultValues(true, false);
    }

    @Test
    public void shouldReverseBindWithDefaultValuesNoConstructor() throws Exception {
        doTestReverseBindWithDefaultValues(false, true);
    }

    private void doTestReverseBindWithDefaultValues(boolean dontSkip, boolean noConstructor) throws Exception {
        Sample target = noConstructor ? new SampleWithoutDefaultConstructor("") : new Sample();
        target.setIntegerValue(new Integer(123));
        DataBinder dataBinder = new DataBinder(target);
        ReverseDataBinder reverseDataBinder = new ReverseDataBinder(dataBinder);
        if (dontSkip) {
            // Only set when skipped to test default is true
            reverseDataBinder.setSkipDefaultValues(false);
        }
        PropertyValues result = reverseDataBinder.reverseBind();
        boolean fullBindExpected = dontSkip || noConstructor;
        assertThat(result.getPropertyValues().length, is(equalTo(fullBindExpected ? 2 : 1)));
        assertThat(result.getPropertyValue("integerValue").getValue(), is(equalTo((Object) "123")));
        if (fullBindExpected) {
            assertThat(result.getPropertyValue("stringValue").getValue(), is(equalTo((Object) "default")));
        }
    }

    public static class Sample {
        private Date dateValue;

        private Integer integerValue;

        private String stringValue = "default";

        private CustomType customTypeValue;

        public Date getDateValue() {
            return this.dateValue;
        }

        public void setDateValue(Date dateValue) {
            this.dateValue = dateValue;
        }

        public Integer getIntegerValue() {
            return this.integerValue;
        }

        public void setIntegerValue(Integer integerValue) {
            this.integerValue = integerValue;
        }

        public String getStringValue() {
            return this.stringValue;
        }

        public void setStringValue(String stringValue) {
            this.stringValue = stringValue;
        }

        public String getNonMutable() {
            return "";
        }

        public CustomType getCustomTypeValue() {
            return this.customTypeValue;
        }

        public void setCustomTypeValue(CustomType customTypeValue) {
            this.customTypeValue = customTypeValue;
        }
    }

    public static class SampleWithoutDefaultConstructor extends Sample {
        public SampleWithoutDefaultConstructor(String argument) {
            super();
        }
    }

    public static class ThrowingPropertyEditor extends PropertyEditorSupport {
        @Override
        public String getAsText() {
            throw new RuntimeException("test error");
        }
    }

    public static final class CustomType {
        private String value;

        private CustomType(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return this.value;
        }

        @Override
        public int hashCode() {
            return this.value.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof CustomType) {
                return this.value.equals(((CustomType) obj).value);
            }
            return super.equals(obj);
        }
    }

    public static final class CustomTypeToStringConverter implements Converter<CustomType, String> {
        public String convert(CustomType source) {
            return source == null ? null : source.toString();
        }
    }

    public static final class StringToCustomTypeConverter implements Converter<String, CustomType> {
        public CustomType convert(String source) {
            return source == null ? null : new CustomType(source);
        }
    }
}