/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cayenne.reflect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.access.types.MockEnum;
import org.apache.cayenne.access.types.MockEnumHolder;
import org.junit.Test;
public class PropertyUtilsTest {
@Test
public void testAccessor() {
Accessor accessor = PropertyUtils.accessor("byteArrayField");
assertNotNull(accessor);
TstJavaBean o1 = createBean();
assertSame(o1.getByteArrayField(), accessor.getValue(o1));
TstJavaBean o2 = new TstJavaBean();
assertNull(o2.getByteArrayField());
accessor.setValue(o2, o1.getByteArrayField());
assertNotNull(o2.getByteArrayField());
assertSame(o1.getByteArrayField(), o2.getByteArrayField());
}
@Test
public void testAccessor_Cache() {
Accessor accessor = PropertyUtils.accessor("p1");
assertNotNull(accessor);
assertSame(accessor, PropertyUtils.accessor("p1"));
assertSame(accessor, PropertyUtils.accessor("p1"));
assertNotSame(accessor, PropertyUtils.accessor("p2"));
}
@Test
public void testAccessor_CacheNested() {
Accessor accessor = PropertyUtils.accessor("p1.p2");
assertNotNull(accessor);
assertSame(accessor, PropertyUtils.accessor("p1.p2"));
assertNotSame(accessor, PropertyUtils.accessor("p1"));
assertNotSame(accessor, PropertyUtils.accessor("p2"));
}
@Test
public void testAccessorNested() {
Accessor accessor = PropertyUtils.accessor("related.byteArrayField");
assertNotNull(accessor);
TstJavaBean o1 = createBean();
o1.setRelated(new TstJavaBean());
o1.getRelated().setByteArrayField(new byte[] { 3, 4, 5 });
assertSame(o1.getRelated().getByteArrayField(), accessor.getValue(o1));
TstJavaBean o2 = new TstJavaBean();
o2.setRelated(new TstJavaBean());
byte[] b1 = new byte[] { 6, 7, 8 };
accessor.setValue(o2, b1);
assertSame(b1, o2.getRelated().getByteArrayField());
}
@Test
public void testAccessorNested_Null() {
Accessor accessor = PropertyUtils.accessor("related.byteArrayField");
assertNotNull(accessor);
TstJavaBean o1 = createBean();
assertNull(accessor.getValue(o1));
}
@Test
public void testGetProperty() {
TstJavaBean o1 = createBean();
assertSame(o1.getByteArrayField(), PropertyUtils.getProperty(o1, "byteArrayField"));
assertSame(o1.getIntegerField(), PropertyUtils.getProperty(o1, "integerField"));
assertEquals(o1.getIntField(), PropertyUtils.getProperty(o1, "intField"));
assertSame(o1.getNumberField(), PropertyUtils.getProperty(o1, "numberField"));
assertSame(o1.getObjectField(), PropertyUtils.getProperty(o1, "objectField"));
assertSame(o1.getStringField(), PropertyUtils.getProperty(o1, "stringField"));
assertEquals(o1.isBooleanField(), PropertyUtils.getProperty(o1, "booleanField"));
}
@Test
public void testGetProperty_Nested() {
TstJavaBean o1 = createBean();
assertNull(PropertyUtils.getProperty(o1, "related.integerField"));
TstJavaBean o1related = new TstJavaBean();
o1related.setIntegerField(44);
o1.setRelated(o1related);
assertEquals(44, PropertyUtils.getProperty(o1, "related.integerField"));
}
@Test
public void testGetProperty_NestedOuter() {
TstJavaBean o1 = createBean();
assertNull(PropertyUtils.getProperty(o1, "related+.integerField"));
TstJavaBean o1related = new TstJavaBean();
o1related.setIntegerField(42);
o1.setRelated(o1related);
assertEquals(42, PropertyUtils.getProperty(o1, "related+.integerField"));
}
@Test
public void testSetProperty() {
TstJavaBean o1 = createBean();
TstJavaBean o2 = new TstJavaBean();
PropertyUtils.setProperty(o2, "byteArrayField", o1.getByteArrayField());
PropertyUtils.setProperty(o2, "integerField", o1.getIntegerField());
PropertyUtils.setProperty(o2, "intField", o1.getIntField());
PropertyUtils.setProperty(o2, "numberField", o1.getNumberField());
PropertyUtils.setProperty(o2, "objectField", o1.getObjectField());
PropertyUtils.setProperty(o2, "stringField", o1.getStringField());
PropertyUtils.setProperty(o2, "booleanField", o1.isBooleanField());
}
@Test
public void testGetPropertyMap() {
Map<String, Object> o1 = createMap();
assertSame(o1.get("byteArrayField"), PropertyUtils.getProperty(o1, "byteArrayField"));
assertSame(o1.get("integerField"), PropertyUtils.getProperty(o1, "integerField"));
assertEquals(o1.get("intField"), PropertyUtils.getProperty(o1, "intField"));
assertSame(o1.get("numberField"), PropertyUtils.getProperty(o1, "numberField"));
assertSame(o1.get("objectField"), PropertyUtils.getProperty(o1, "objectField"));
assertSame(o1.get("stringField"), PropertyUtils.getProperty(o1, "stringField"));
assertEquals(o1.get("booleanField"), PropertyUtils.getProperty(o1, "booleanField"));
}
@Test
public void testSetProperty_Nested() {
TstJavaBean o1 = createBean();
TstJavaBean o1related = new TstJavaBean();
o1related.setIntegerField(44);
o1.setRelated(o1related);
PropertyUtils.setProperty(o1, "related.integerField", 55);
assertEquals(Integer.valueOf(55), o1related.getIntegerField());
}
@Test
public void testSetProperty_Null() {
TstJavaBean o1 = createBean();
PropertyUtils.setProperty(o1, "related.integerField", 55);
}
@Test
public void testSetPropertyMap() {
Map<String, Object> o1 = createMap();
Map<String, Object> o2 = new HashMap<>();
PropertyUtils.setProperty(o2, "byteArrayField", o1.get("byteArrayField"));
PropertyUtils.setProperty(o2, "integerField", o1.get("integerField"));
PropertyUtils.setProperty(o2, "intField", o1.get("intField"));
PropertyUtils.setProperty(o2, "numberField", o1.get("numberField"));
PropertyUtils.setProperty(o2, "objectField", o1.get("objectField"));
PropertyUtils.setProperty(o2, "stringField", o1.get("stringField"));
PropertyUtils.setProperty(o2, "booleanField", o1.get("booleanField"));
assertEquals(o1, o2);
}
@Test
public void testSetConverted() {
TstJavaBean o1 = new TstJavaBean();
// Object -> String
Object object = new Object();
PropertyUtils.setProperty(o1, "stringField", object);
assertEquals(object.toString(), o1.getStringField());
// String to number
PropertyUtils.setProperty(o1, "integerField", "25");
assertEquals(new Integer(25), o1.getIntegerField());
// string to byte primitive
PropertyUtils.setProperty(o1, "byteField", "2");
assertEquals(2, o1.getByteField());
// string to short primitive
PropertyUtils.setProperty(o1, "shortField", "3");
assertEquals(3, o1.getShortField());
// string to int primitive
PropertyUtils.setProperty(o1, "intField", "28");
assertEquals(28, o1.getIntField());
// string to long primitive
PropertyUtils.setProperty(o1, "longField", "29");
assertEquals(29, o1.getLongField());
// string to float primitive
PropertyUtils.setProperty(o1, "floatField", "4.5");
assertEquals(4.5f, o1.getFloatField(), 0);
// string to double primitive
PropertyUtils.setProperty(o1, "doubleField", "5.5");
assertEquals(5.5, o1.getDoubleField(), 0);
// string to boolean
PropertyUtils.setProperty(o1, "booleanField", "true");
assertTrue(o1.isBooleanField());
PropertyUtils.setProperty(o1, "booleanField", "false");
assertFalse(o1.isBooleanField());
// int to boolean
PropertyUtils.setProperty(o1, "booleanField", 1);
assertTrue(o1.isBooleanField());
PropertyUtils.setProperty(o1, "booleanField", 0);
assertFalse(o1.isBooleanField());
// long to boolean
PropertyUtils.setProperty(o1, "booleanField", 1L);
assertTrue(o1.isBooleanField());
PropertyUtils.setProperty(o1, "booleanField", 0L);
assertFalse(o1.isBooleanField());
// long to date
PropertyUtils.setProperty(o1, "dateField", 0L);
assertEquals(new Date(0L), o1.getDateField());
// long to timestamp
PropertyUtils.setProperty(o1, "timestampField", 0L);
assertEquals(new Timestamp(0L), o1.getTimestampField());
// arbitrary string/object to field
PropertyUtils.setProperty(o1, "stringBuilderField", "abc");
assertEquals("abc", o1.getStringBuilderField().toString());
}
@Test
public void testSetConvertedWithCustomConverter() {
// save old converter for restore
Converter<Date> oldConverter = ConverterFactory.factory.getConverter(Date.class);
try {
ConverterFactory.addConverter(Date.class, new Converter<Date>() {
@Override
protected Date convert(Object value, Class<Date> type) {
if (value == null)
return null;
if (value instanceof Date) {
return (Date) value;
}
if (value instanceof String) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse((String) value);
} catch (ParseException e) {
throw new CayenneRuntimeException("Unable to convert '" + value + "' to a Date", e);
}
}
throw new CayenneRuntimeException("Unable to convert '" + value + "' to a Date");
}
});
TstJavaBean o1 = new TstJavaBean();
// String to date
PropertyUtils.setProperty(o1, "dateField", "2013-08-01");
Calendar cal = new GregorianCalendar(2013, 7, 1, 0, 0, 0);
assertEquals(cal.getTime(), o1.getDateField());
} finally {
// restore global date converter
ConverterFactory.addConverter(Date.class, oldConverter);
}
}
@Test
public void testSetNull() {
TstJavaBean o1 = new TstJavaBean();
o1.setStringField("xyz");
PropertyUtils.setProperty(o1, "stringField", null);
assertNull(o1.getStringField());
o1.setBooleanField(true);
PropertyUtils.setProperty(o1, "booleanField", null);
assertEquals(false, o1.isBooleanField());
o1.setByteField((byte) 2);
PropertyUtils.setProperty(o1, "byteField", null);
assertEquals((byte) 0, o1.getByteField());
o1.setShortField((short) 3);
PropertyUtils.setProperty(o1, "shortField", null);
assertEquals((short) 0, o1.getShortField());
o1.setIntField(99);
PropertyUtils.setProperty(o1, "intField", null);
assertEquals(0, o1.getIntField());
o1.setLongField(98);
PropertyUtils.setProperty(o1, "longField", null);
assertEquals(0L, o1.getLongField());
o1.setFloatField(4.5f);
PropertyUtils.setProperty(o1, "floatField", null);
assertEquals(0.0f, o1.getFloatField(), 0);
o1.setDoubleField(5.5f);
PropertyUtils.setProperty(o1, "doubleField", null);
assertEquals(0.0, o1.getDoubleField(), 0);
}
@Test
public void testSetConvertedEnum() {
MockEnumHolder o1 = new MockEnumHolder();
// String to Enum
PropertyUtils.setProperty(o1, "mockEnum", "b");
assertSame(MockEnum.b, o1.getMockEnum());
// check that regular converters still work
PropertyUtils.setProperty(o1, "number", "445");
assertEquals(445, o1.getNumber());
}
private TstJavaBean createBean() {
TstJavaBean o1 = new TstJavaBean();
o1.setByteArrayField(new byte[] { 1, 2, 3 });
o1.setIntegerField(33);
o1.setIntField(-44);
o1.setNumberField(new BigDecimal("11111"));
o1.setObjectField(new Object());
o1.setStringField("aaaaa");
o1.setBooleanField(true);
return o1;
}
private Map<String, Object> createMap() {
Map<String, Object> o1 = new HashMap<>();
o1.put("byteArrayField", new byte[] { 1, 2, 3 });
o1.put("integerField", 33);
o1.put("intField", -44);
o1.put("numberField", new BigDecimal("11111"));
o1.put("objectField", new Object());
o1.put("stringField", "aaaaa");
o1.put("booleanField", Boolean.TRUE);
return o1;
}
}