cat.albirar.framework.dynabean.annotations.DynaBeanAnnotationsTest.java Source code

Java tutorial

Introduction

Here is the source code for cat.albirar.framework.dynabean.annotations.DynaBeanAnnotationsTest.java

Source

/*
 * This file is part of "dynabean".
 * 
 * "dynabean" is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * "dynabean" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with calendar. If not, see
 * <http://www.gnu.org/licenses/>.
 * 
 * Copyright (C) 2015 Octavi Forns <ofornes@albirar.cat>
 */

package cat.albirar.framework.dynabean.annotations;

import java.beans.PropertyEditorSupport;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.AbstractMap;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;
import java.util.Vector;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.util.StringUtils;

import cat.albirar.framework.dynabean.impl.DefaultDynaBeanFactory;
import cat.albirar.framework.dynabean.impl.DynaBeanDescriptorTest;
import cat.albirar.framework.dynabean.impl.IDynaBeanImplementationFactory;
import cat.albirar.framework.dynabean.impl.models.test.AnnotatedModelImpl;
import cat.albirar.framework.dynabean.impl.models.test.IAnnotatedModel;
import cat.albirar.framework.dynabean.impl.models.test.IAnnotatedParentModel;
import cat.albirar.framework.dynabean.impl.models.test.SimpleModelImpl;

/**
 * DynBean annotations tests.
 * 
 * @author <a href="mailto:ofornes@albirar.cat">Octavi Forns ofornes@albirar.cat</a>
 * @since 2.0
 */
public class DynaBeanAnnotationsTest {
    static final int DATE_TEST_CED_YEAR = 2012;

    static final int DATE_TEST_CED_MONTH = 10;

    static final int DATE_TEST_CED_DAY = 12;

    static final String DATE_TEST_CED = "" + DATE_TEST_CED_YEAR + "" + DATE_TEST_CED_MONTH + "" + DATE_TEST_CED_DAY;

    static final String PATTERN_DATE_TEST_CED = "yyyyMMdd";

    static final int INT_TEST_CED = 255;

    static final String ARRAY_VALUES_1 = "10";
    static final String ARRAY_VALUES_2 = "20";
    static final String ARRAY_VALUES_3 = "30";
    static final String[] ARRAY_VALUES_STRING = { ARRAY_VALUES_1, ARRAY_VALUES_2, ARRAY_VALUES_3 };
    static final float[] ARRAY_VALUES_FLOAT = { Float.parseFloat(ARRAY_VALUES_1), Float.parseFloat(ARRAY_VALUES_2),
            Float.parseFloat(ARRAY_VALUES_3) };

    private IDynaBeanImplementationFactory factory;

    @Before
    public void initTest() {
        factory = new DefaultDynaBeanFactory();
    }

    /**
     * Test the {@link PropertyDefaultValue} annotation.
     */
    @Test
    public void testDefaultValues() {
        IAnnotatedModel model;

        model = factory.newDynaBean(IAnnotatedModel.class);
        // Assert default values
        Assert.assertTrue(model.isPending());
        Assert.assertEquals(Vector.class, model.getNamesList().getClass());
        Assert.assertEquals(IAnnotatedModel.DEFAULT_AMOUNT, model.getAmount(), 0D);
        Assert.assertArrayEquals(IAnnotatedModel.DEFAULT_OTHER_NAMES, model.getOtherNames());
        Assert.assertArrayEquals(IAnnotatedModel.DEFAULT_OTHER_AMOUNTS, model.getOtherAmounts(), 0.0D);
    }

    /**
     * Test the {@link DynaBean} autodetection feature.
     */
    @Test
    public void testDynabeanAutodetection() {
        IAnnotatedParentModel model;

        model = factory.newDynaBean(IAnnotatedParentModel.class);
        Assert.assertNull(model.getId());
        Assert.assertNotNull(model.getSubmodel());
        Assert.assertNotNull(model.getSubmodel().getNamesList());
        Assert.assertNull(model.getDynabeanNotAnnotatedModel());
        Assert.assertNotNull(model.getSimpleModel());
        Assert.assertEquals(SimpleModelImpl.class, model.getSimpleModel().getClass());
    }

    /**
     * Test the clone feature with annotated model.
     */
    @Test
    public void testClone() {
        IAnnotatedModel m1, m2;

        m1 = factory.newDynaBean(IAnnotatedModel.class);
        m2 = m1.clone();
        Assert.assertEquals(m1, m2);
        // Test clone of date
        Assert.assertNotSame(m1.getNamesList(), m2.getNamesList());
        Assert.assertNotSame(m1.getOtherAmounts(), m2.getOtherAmounts());
        Assert.assertNotSame(m1.getOtherNames(), m2.getOtherNames());
    }

    /**
     * Test the clone feature with annotated model.
     */
    @Test
    public void testCloneComplex() {
        IAnnotatedModel m1, m2;
        IAnnotatedParentModel pm1, pm2;

        pm1 = factory.newDynaBean(IAnnotatedParentModel.class);
        m1 = factory.newDynaBean(IAnnotatedModel.class);
        m1.getNamesList().clear();
        m1.getNamesList().add("X");
        m1.getNamesList().add("Y");
        m1.getNamesList().add("Z");
        pm1.setOtherSubmodels(new Vector<IAnnotatedModel>());
        pm1.getOtherSubmodels().add(m1);
        pm1.setId("WWW");

        pm2 = pm1.clone();

        Assert.assertEquals(pm1, pm2);
        Assert.assertNotSame(pm1, pm2);

        Assert.assertEquals(pm1.getOtherSubmodels(), pm2.getOtherSubmodels());
        Assert.assertNotSame(pm1.getOtherSubmodels(), pm2.getOtherSubmodels());
        m2 = pm2.getOtherSubmodels().get(0);
        Assert.assertEquals(m1, m2);
        Assert.assertNotSame(m1, m2);
    }

    /**
     * Test the hashCode feature with annotated model.
     */
    @Test
    public void testHashsCode() {
        IAnnotatedModel m1, m2;
        int n;

        m1 = factory.newDynaBean(IAnnotatedModel.class);
        m2 = m1.clone();

        for (n = 0; n < 10; n++) {
            Assert.assertEquals(m1.hashCode(), m2.hashCode());
        }
    }

    /**
     * Test the serialization feature.
     */
    @Test
    public void testSerialize() throws Exception {
        ByteArrayOutputStream baos;
        IAnnotatedModel model, model1;
        ObjectOutputStream out;
        ByteArrayInputStream bais;
        ObjectInputStream in;

        // Prepare bean
        model = factory.newDynaBean(IAnnotatedModel.class);

        // Prepare stream
        baos = new ByteArrayOutputStream();
        out = new ObjectOutputStream(baos);
        out.writeObject(model);
        out.flush();

        // Deserialize
        bais = new ByteArrayInputStream(baos.toByteArray());
        in = new ObjectInputStream(bais);
        model1 = (IAnnotatedModel) in.readObject();

        // Test if equals
        Assert.assertNotNull(model1);
        Assert.assertEquals(model, model1);
        Assert.assertNotSame(model, model1);
    }

    /**
     * Test the clone with explicit bean implementation.
     */
    @Test
    public void testMixedEquals() {
        IAnnotatedModel m1, m2;
        List<String> names;
        double[] oamount = { 10.5D, 125.223D, 998.66271D };

        m2 = factory.newDynaBean(IAnnotatedModel.class);
        m1 = new AnnotatedModelImpl();
        m1.setId("XX");
        m1.setAmount(IAnnotatedModel.DEFAULT_AMOUNT + 2.0D);
        names = new Vector<String>();
        names.add("N1");
        names.add("N2");
        names.add("N3");
        m1.setNamesList(names);
        m1.setPending(true);
        names.clear();
        names.add("ON1");
        names.add("ON2");
        names.add("ON3");
        names.add("ON4");
        m1.setOtherNames(names.toArray(new String[] {}));
        m1.setOtherAmounts(oamount);

        m2.setId(m1.getId());
        m2.setAmount(m1.getAmount());
        m2.setNamesList(cloneList(m1.getNamesList()));
        m2.setOtherAmounts(oamount);
        m2.setOtherNames(names.toArray(new String[] {}));

        Assert.assertTrue(m2.equals(m1));
        m2.setOtherNames(new String[] { "A", "B", "C" });
        Assert.assertFalse(m2.equals(m1));
    }

    /**
     * Test for {@link DynaBean} annotated property with {@link IWrongUseOfDynaBeanAnnotationModelA}.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testAnnotatedPropertyErrorModelA() {
        factory.newDynaBean(IWrongUseOfDynaBeanAnnotationModelA.class);
    }

    /**
     * Test for {@link DynaBean} annotated property with {@link IWrongUseOfDynaBeanAnnotationModelB}.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testAnnotatedPropertyErrorModelB() {
        factory.newDynaBean(IWrongUseOfDynaBeanAnnotationModelB.class);
    }

    /**
     * Test for {@link DynaBean} annotated property with {@link IWrongUseOfDynaBeanAnnotationModelC}.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testAnnotatedPropertyErrorModelC() {
        factory.newDynaBean(IWrongUseOfDynaBeanAnnotationModelC.class);
    }

    /**
     * Test for {@link DynaBean} annotated property with {@link IWrongUseOfDynaBeanAnnotationModelD}.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testAnnotatedPropertyErrorModelD() {
        factory.newDynaBean(IWrongUseOfDynaBeanAnnotationModelD.class);
    }

    /**
     * Test for {@link DynaBean} annotated property with {@link IWrongUseOfDynaBeanAnnotationModelE}.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testAnnotatedPropertyErrorModelE() {
        factory.newDynaBean(IWrongUseOfDynaBeanAnnotationModelE.class);
    }

    /**
     * Test if a {@link DynaBean} annotated implementation interface is detected.
     */
    @Test
    public void testAnnotatedPropertyDynBeanImplementation() {
        IDynaBeanExplicitDynaBeanProperty d;

        d = factory.newDynaBean(IDynaBeanExplicitDynaBeanProperty.class);
        Assert.assertNotNull(d.getModel());
    }

    /**
     * Test use of editors by item type. This test case sets a property editor by item type for {@link java.util.Date}.
     * Gets or set the property for {@link IDynaBeanDescriptorTestValidModel#setFieldDate(Date)} and check if value is
     * correctly assigned.
     */
    @Test
    public void testPropertyEditorByItemType() {
        IDynaBeanDescriptorDates model;
        Calendar date;
        CustomDateEditor cde;

        cde = new CustomDateEditor(new SimpleDateFormat(PATTERN_DATE_TEST_CED), false);
        factory.getPropertyEditorRegistry().registerCustomEditor(Date.class, null, cde);

        model = factory.newDynaBean(IDynaBeanDescriptorDates.class);
        Assert.assertNotNull(model.getAnotherFieldDate());
        // Data should to be DATE_TEST_CED
        date = Calendar.getInstance();
        date.setTimeInMillis(model.getFieldDate().getTime());
        Assert.assertEquals(DATE_TEST_CED_DAY, date.get(Calendar.DATE));
        Assert.assertEquals(DATE_TEST_CED_MONTH, date.get(Calendar.MONTH) + 1);
        Assert.assertEquals(DATE_TEST_CED_YEAR, date.get(Calendar.YEAR));
    }

    /**
     * Test use of automatic editor created with the values if {@link PropertyDefaultValue} annotation.
     */
    @Test
    public void testPropertyAutoEditorDateAndCalendar() {
        IDynaBeanDescriptorDates model;
        Calendar date;

        model = factory.newDynaBean(IDynaBeanDescriptorDates.class);
        Assert.assertNotNull(model.getFieldDate());
        // Data should to be DATE_TEST_CED
        date = Calendar.getInstance();
        date.setTimeInMillis(model.getFieldDate().getTime());
        Assert.assertEquals(DATE_TEST_CED_DAY, date.get(Calendar.DATE));
        Assert.assertEquals(DATE_TEST_CED_MONTH, date.get(Calendar.MONTH) + 1);
        Assert.assertEquals(DATE_TEST_CED_YEAR, date.get(Calendar.YEAR));

        Assert.assertNotNull(model.getFieldCalendar());
        // Data should to be DATE_TEST_CED
        date = Calendar.getInstance();
        date.setTimeInMillis(model.getFieldCalendar().getTimeInMillis());
        Assert.assertEquals(DATE_TEST_CED_DAY, date.get(Calendar.DATE));
        Assert.assertEquals(DATE_TEST_CED_MONTH, date.get(Calendar.MONTH) + 1);
        Assert.assertEquals(DATE_TEST_CED_YEAR, date.get(Calendar.YEAR));
    }

    /**
     * Test use of editors by path. This test case sets a property editor by path for
     * {@link IDynaBeanDescriptorTestValidModel#setFieldInt(int)}. The property editor multiply by two the original
     * value to be assigned Gets or set the property for {@link IDynaBeanDescriptorTestValidModel#setFieldInt(int)} and
     * check if value is correctly assigned as made by editor. Gets or set the property for
     * {@link IDynaBeanDescriptorTestValidModel#setFieldAnotherInt(int)} and check if value is correctly assigned
     * without the modifications made by editor.
     */
    @Test
    public void testPropertyEditorByPath() {
        IDynaBeanDescriptorDates model;

        factory.getPropertyEditorRegistry().registerCustomEditor(int.class,
                IDynaBeanDescriptorDates.class.getName() + ".fieldAnotherInt", new CustomEditorForInteger());
        model = factory.newDynaBean(IDynaBeanDescriptorDates.class);
        Assert.assertEquals(INT_TEST_CED * 2, model.getFieldAnotherInt());
    }

    @Test
    public void testNoPropertyEditorFound() {
        IDynaBeanDescriptorDates model;

        model = factory.newDynaBean(IDynaBeanDescriptorDates.class);
        Assert.assertEquals(INT_TEST_CED, model.getFieldAnotherInt());
        Assert.assertNotNull(model.getFieldDate());
    }

    /**
     * Test for annotated {@link PropertyDefaultValue} property array.
     */
    @Test
    public void testAnnotatedPropertyArray() {
        IAnnotatedPropertyArray d;

        d = factory.newDynaBean(IAnnotatedPropertyArray.class);
        Assert.assertNotNull(d.getFieldArrayFloat());
        Assert.assertArrayEquals(ARRAY_VALUES_FLOAT, d.getFieldArrayFloat(), 0.0F);
    }

    /**
     * Test default instantiation of collection property without default implementation. 
     */
    @Test
    public void testDynaBeanWithCollectionWithoutDefaultImplementation() {
        IDynaBeanWithCollectionWithoutDefaultImplementation d;
        int n;

        d = factory.newDynaBean(IDynaBeanWithCollectionWithoutDefaultImplementation.class);
        Assert.assertNotNull(d.getFieldList());
        Assert.assertEquals(ARRAY_VALUES_STRING.length, d.getFieldList().size());
        for (n = 0; n < ARRAY_VALUES_STRING.length; n++) {
            Assert.assertEquals(ARRAY_VALUES_STRING[n], d.getFieldList().get(n));
        }
    }

    interface IDynaBeanWithCollectionWithoutDefaultImplementation {
        @PropertyDefaultValue(value = { ARRAY_VALUES_1, ARRAY_VALUES_2, ARRAY_VALUES_3 })
        public List<String> getFieldList();

        public void setFieldList(List<String> fieldList);
    }

    /**
     * Test for annotated {@link PropertyDefaultValue} property with a {@link PropertyDefaultValue#implementation()} without constructor.
     */
    @Test(expected = IllegalArgumentException.class)
    public void testClassWithoutConstructor() {
        factory.newDynaBean(IDynaBeanDefaultImplementationError.class);
    }

    /**
     * For test default error on instantiate.
     */
    interface IClassWithoutConstructor {
        public int getFieldInt();

        public void setFieldInt(int fieldInt);
    }

    /**
     * For test default error on instantiate.
     */
    class ClassWithoutConstructor implements IClassWithoutConstructor {

        @Override
        public int getFieldInt() {
            return 0;
        }

        @Override
        public void setFieldInt(int fieldInt) {
        }
    }

    /**
     * For test default error on instantiate.
     */
    interface IDynaBeanDefaultImplementationError {
        @PropertyDefaultValue(implementation = ClassWithoutConstructor.class)
        public IClassWithoutConstructor getFieldClass();

        public void setFieldClass(IClassWithoutConstructor fieldClass);
    }

    /** To test detection of implementation dynabean annotated interface. */
    interface IDynaBeanExplicitDynaBeanProperty {
        @PropertyDefaultValue(implementation = IAnnotatedModel.class)
        public IAnnotatedModel getModel();

        public void setModel(IAnnotatedModel model);
    }

    /**
     * For test {@link DynaBeanDescriptorTest#testPropertyEditorByItemType()} and
     * {@link DynaBeanDescriptorTest#testPropertyEditorByPath()}.
     */
    interface IDynaBeanDescriptorDates {
        public int getFieldAnotherInt();

        @PropertyDefaultValue("" + INT_TEST_CED)
        public void setFieldAnotherInt(int fieldAnotherInt);

        @PropertyDefaultValue(value = DATE_TEST_CED, pattern = PATTERN_DATE_TEST_CED)
        public Date getFieldDate();

        public void setFieldDate(Date fieldDate);

        @PropertyDefaultValue(value = DATE_TEST_CED, pattern = PATTERN_DATE_TEST_CED)
        public Calendar getFieldCalendar();

        public void setFieldCalendar(Calendar fieldDate);

        @PropertyDefaultValue(value = DATE_TEST_CED)
        public Date getAnotherFieldDate();

        public void setAnotherFieldDate(Date fieldDate);
    }

    /**
     * For test {@link DynaBeanDescriptorTest#testPropertyEditorByPath()}.
     */
    class CustomEditorForInteger extends PropertyEditorSupport {
        @Override
        public String getAsText() {
            if (getValue() != null) {
                return Integer.toString((Integer) getValue());
            }
            return "0";
        }

        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            int n;

            if (StringUtils.hasText(text)) {
                try {
                    n = Integer.parseInt(text);
                } catch (NumberFormatException e) {
                    n = 0;
                }
            } else {
                n = 0;
            }
            setValue(Integer.valueOf(n * 2));
        }
    }

    /** To check detection of wrong use of annotations. */
    interface IWrongUseOfDynaBeanAnnotationModelA {
        public int getIntField();

        public void setIntField(int intField);

        @DynaBean(defaultInstantiate = true)
        public TreeMap<String, String> getMapProperty();

        public void setMapProperty(TreeMap<String, String> mapProperty);

        @PropertyDefaultValue()
        public String getStringField();

        public void setStringField(String stringField);
    }

    /** To check detection of wrong use of annotations. */
    interface IWrongUseOfDynaBeanAnnotationModelB {
        public int getIntField();

        public void setIntField(int intField);

        public TreeMap<String, String> getMapProperty();

        public void setMapProperty(TreeMap<String, String> mapProperty);

        @PropertyDefaultValue()
        public String getStringField();

        public void setStringField(String stringField);
    }

    /** To check detection of wrong use of annotations. */
    interface IWrongUseOfDynaBeanAnnotationModelC {
        public int getIntField();

        public void setIntField(int intField);

        @PropertyDefaultValue(implementation = List.class)
        public TreeMap<String, String> getMapProperty();

        public void setMapProperty(TreeMap<String, String> mapProperty);

    }

    /** To check detection of wrong use of annotations. */
    interface IWrongUseOfDynaBeanAnnotationModelD {
        public int getIntField();

        public void setIntField(int intField);

        @PropertyDefaultValue(implementation = AbstractMap.class)
        public TreeMap<String, String> getMapProperty();

        public void setMapProperty(TreeMap<String, String> mapProperty);

    }

    /** To check detection of wrong use of annotations. */
    interface IWrongUseOfDynaBeanAnnotationModelE {
        public int getIntField();

        public void setIntField(int intField);

        @PropertyDefaultValue(value = "123", pattern = "RRR")
        public TreeMap<String, String> getMapProperty();

        public void setMapProperty(TreeMap<String, String> mapProperty);

    }

    interface IAnnotatedPropertyArray {
        @PropertyDefaultValue(value = { ARRAY_VALUES_1, ARRAY_VALUES_2, ARRAY_VALUES_3 })
        public float[] getFieldArrayFloat();

        public void setFieldArrayFloat(float[] fieldArrayFloat);

        @PropertyDefaultValue(value = { ARRAY_VALUES_1, ARRAY_VALUES_2, ARRAY_VALUES_3 })
        public String[] getFieldArrayString();

        public void setFieldArrayString(String[] fieldArrayString);
    }

    /**
     * Clones a list.
     * @param list The list
     * @return The cloned list
     */
    private <T> List<T> cloneList(List<T> list) {
        List<T> dest;

        dest = new Vector<T>();
        for (T e : list) {
            dest.add(e);
        }
        return dest;
    }
}