| /* |
| * 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 |
| * |
| * https://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.commons.beanutils2.sql; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertInstanceOf; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| |
| import java.math.BigDecimal; |
| import java.sql.Date; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.sql.Types; |
| import java.util.List; |
| |
| import org.apache.commons.beanutils2.DynaBean; |
| import org.apache.commons.beanutils2.DynaProperty; |
| import org.junit.jupiter.api.AfterEach; |
| import org.junit.jupiter.api.BeforeEach; |
| import org.junit.jupiter.api.Test; |
| |
| /** |
| * Test accessing RowSets via DynaBeans. |
| */ |
| class DynaRowSetTest { |
| |
| private static class CustomTimestamp { |
| private final long timestamp = new java.util.Date().getTime(); |
| |
| @Override |
| public String toString() { |
| return "CustomTimestamp[" + timestamp + "]"; |
| } |
| } |
| |
| /** |
| * A proxy ResultSet implementation that returns Timstamp for a date column. |
| * |
| * See issue# https://issues.apache.org/jira/browse/BEANUTILS-142 |
| */ |
| private static class TestResultSetInconsistent extends TestResultSet { |
| |
| public TestResultSetInconsistent(final ResultSetMetaData metaData) { |
| super(metaData); |
| } |
| |
| /** |
| * Gets an columns's value |
| * |
| * @param columnName Name of the column |
| * @return The column value |
| * @throws SQLException if an error occurs |
| */ |
| @Override |
| public Object getObject(final String columnName) throws SQLException { |
| if ("timestampProperty".equals(columnName)) { |
| return new CustomTimestamp(); |
| } |
| return super.getObject(columnName); |
| } |
| |
| } |
| |
| /** |
| * A proxy ResultSetMetaData implementation that returns a class name that is inconsistent with the type returned by the ResultSet.getObject() method. |
| * |
| * See issue# https://issues.apache.org/jira/browse/BEANUTILS-142 |
| */ |
| private static class TestResultSetMetaDataInconsistent extends TestResultSetMetaData { |
| |
| /** |
| * This method substitues class names of "java.sql.Timestamp" with "java.sql.Date" to test inconsistent JDBC drivers. |
| * |
| * @param columnIndex The column index |
| * @return The column class name |
| * @throws SQLException if an error occurs |
| */ |
| @Override |
| public String getColumnClassName(final int columnIndex) throws SQLException { |
| final String columnName = getColumnName(columnIndex); |
| if (columnName.equals("dateProperty")) { |
| return java.sql.Timestamp.class.getName(); |
| } |
| if (columnName.equals("timestampProperty")) { |
| return CustomTimestamp.class.getName(); |
| } |
| return super.getColumnClassName(columnIndex); |
| } |
| } |
| |
| /** |
| * The mock result set DynaClass to be tested. |
| */ |
| protected RowSetDynaClass dynaClass; |
| |
| /** |
| * Names of the columns for this test. Must match the order they are defined in {@link TestResultSetMetaData}, and must be all lower case. |
| */ |
| protected String[] columns = { "bigdecimalproperty", "booleanproperty", "byteproperty", "dateproperty", "doubleproperty", "floatproperty", "intproperty", |
| "longproperty", "nullproperty", "shortproperty", "stringproperty", "timeproperty", "timestampproperty" }; |
| |
| /** |
| * Sets up instance variables required by this test case. |
| */ |
| @BeforeEach |
| public void setUp() throws Exception { |
| |
| dynaClass = new RowSetDynaClass(TestResultSet.createProxy()); |
| |
| } |
| |
| /** |
| * Tear down instance variables required by this test case. |
| */ |
| @AfterEach |
| public void tearDown() { |
| |
| dynaClass = null; |
| |
| } |
| |
| @Test |
| void testGetDynaProperties() { |
| |
| final DynaProperty[] dynaProps = dynaClass.getDynaProperties(); |
| assertNotNull(dynaProps, "dynaProps exists"); |
| assertEquals(columns.length, dynaProps.length, "dynaProps length"); |
| for (int i = 0; i < columns.length; i++) { |
| assertEquals(columns[i], dynaProps[i].getName(), "Property " + columns[i]); |
| } |
| |
| } |
| |
| @Test |
| void testGetDynaProperty() { |
| // Invalid argument test |
| assertThrows(NullPointerException.class, () -> dynaClass.getDynaProperty(null)); |
| // Negative test |
| DynaProperty dynaProp = dynaClass.getDynaProperty("unknownProperty"); |
| assertNull(dynaProp, "unknown property returns null"); |
| // Positive test |
| dynaProp = dynaClass.getDynaProperty("stringproperty"); |
| assertNotNull(dynaProp, "string property exists"); |
| assertEquals("stringproperty", dynaProp.getName(), "string property name"); |
| assertEquals(String.class, dynaProp.getType(), "string property class"); |
| } |
| |
| @Test |
| void testGetName() { |
| assertEquals("org.apache.commons.beanutils2.sql.RowSetDynaClass", dynaClass.getName(), "DynaClass name"); |
| } |
| |
| /** |
| * Test issues associated with Oracle JDBC driver. |
| * |
| * See issue# https://issues.apache.org/jira/browse/BEANUTILS-142 |
| * |
| * @throws Exception if an error occurs |
| */ |
| @Test |
| void testInconsistentOracleDriver() throws Exception { |
| |
| final ResultSetMetaData metaData = TestResultSetMetaData.createProxy(new TestResultSetMetaDataInconsistent()); |
| final ResultSet resultSet = TestResultSet.createProxy(new TestResultSetInconsistent(metaData)); |
| |
| // Date Column returns "java.sql.Timestamp" for the column class name but ResultSet getObject |
| // returns a java.sql.Date value |
| final int dateColIdx = 4; |
| assertEquals("dateProperty", metaData.getColumnName(dateColIdx), "Date Meta Name"); |
| assertEquals("java.sql.Timestamp", metaData.getColumnClassName(dateColIdx), "Date Meta Class"); |
| assertEquals(Types.DATE, metaData.getColumnType(dateColIdx), "Date Meta Type"); |
| assertEquals(Date.class, resultSet.getObject("dateProperty").getClass(), "Date ResultSet Value"); |
| |
| // Timestamp column class returns a custom Timestamp impl for the column class name and ResultSet getObject |
| final int timestampColIdx = 13; |
| assertEquals("timestampProperty", metaData.getColumnName(timestampColIdx), "Timestamp Meta Name"); |
| assertEquals(CustomTimestamp.class.getName(), metaData.getColumnClassName(timestampColIdx), "Timestamp Meta Class"); |
| assertEquals(Types.TIMESTAMP, metaData.getColumnType(timestampColIdx), "Timestamp Meta Type"); |
| assertEquals(CustomTimestamp.class, resultSet.getObject("timestampProperty").getClass(), "Timestamp ResultSet Value"); |
| |
| final RowSetDynaClass inconsistentDynaClass = new RowSetDynaClass(resultSet); |
| final DynaBean firstRow = inconsistentDynaClass.getRows().get(0); |
| Class<?> expectedType; |
| DynaProperty property; |
| |
| // Test Date |
| property = firstRow.getDynaClass().getDynaProperty("dateproperty"); |
| expectedType = java.sql.Date.class; |
| assertEquals(expectedType, property.getType(), "Date Class"); |
| assertEquals(expectedType, firstRow.get(property.getName()).getClass(), "Date Value"); |
| |
| // Test Timestamp |
| property = firstRow.getDynaClass().getDynaProperty("timestampproperty"); |
| expectedType = java.sql.Timestamp.class; |
| assertEquals(expectedType, property.getType(), "Timestamp Class"); |
| assertEquals(expectedType, firstRow.get(property.getName()).getClass(), "Timestamp Value"); |
| } |
| |
| @Test |
| void testLimitedRows() throws Exception { |
| |
| // created one with low limit |
| final RowSetDynaClass limitedDynaClass = new RowSetDynaClass(TestResultSet.createProxy(), 3); |
| final List<DynaBean> rows = limitedDynaClass.getRows(); |
| assertNotNull(rows, "list exists"); |
| assertEquals(3, rows.size(), "limited row count"); |
| |
| } |
| |
| @Test |
| void testListCount() { |
| |
| final List<DynaBean> rows = dynaClass.getRows(); |
| assertNotNull(rows, "list exists"); |
| assertEquals(5, rows.size(), "list row count"); |
| |
| } |
| |
| @Test |
| void testListResults() { |
| |
| // Grab the third row |
| final List<DynaBean> rows = dynaClass.getRows(); |
| final DynaBean row = rows.get(2); |
| |
| // Invalid argument test |
| assertThrows(IllegalArgumentException.class, () -> row.get("unknownProperty")); |
| |
| // Verify property values |
| |
| final Object bigDecimalProperty = row.get("bigdecimalproperty"); |
| assertNotNull(bigDecimalProperty, "bigDecimalProperty exists"); |
| assertInstanceOf(BigDecimal.class, bigDecimalProperty, "bigDecimalProperty type"); |
| assertEquals(123.45, ((BigDecimal) bigDecimalProperty).doubleValue(), 0.005, "bigDecimalProperty value"); |
| |
| final Object intProperty = row.get("intproperty"); |
| assertNotNull(intProperty, "intProperty exists"); |
| assertInstanceOf(Integer.class, intProperty, "intProperty type"); |
| assertEquals(103, ((Integer) intProperty).intValue(), "intProperty value"); |
| |
| final Object nullProperty = row.get("nullproperty"); |
| assertNull(nullProperty, "nullProperty null"); |
| |
| final Object stringProperty = row.get("stringproperty"); |
| assertNotNull(stringProperty, "stringProperty exists"); |
| assertInstanceOf(String.class, stringProperty, "stringProperty type"); |
| assertEquals("This is a string", (String) stringProperty, "stringProperty value"); |
| |
| } |
| |
| /** |
| * Test normal case column names (i.e. not converted to lower case) |
| */ |
| @Test |
| void testListResultsNormalCase() throws Exception { |
| final RowSetDynaClass dynaClass = new RowSetDynaClass(TestResultSet.createProxy(), false); |
| |
| // Grab the third row |
| final List<DynaBean> rows = dynaClass.getRows(); |
| final DynaBean row = rows.get(2); |
| |
| // Invalid argument test |
| assertThrows(IllegalArgumentException.class, () -> row.get("unknownProperty")); |
| |
| // Verify property values |
| |
| final Object bigDecimalProperty = row.get("bigDecimalProperty"); |
| assertNotNull(bigDecimalProperty, "bigDecimalProperty exists"); |
| assertInstanceOf(BigDecimal.class, bigDecimalProperty, "bigDecimalProperty type"); |
| assertEquals(123.45, ((BigDecimal) bigDecimalProperty).doubleValue(), 0.005, "bigDecimalProperty value"); |
| |
| final Object intProperty = row.get("intProperty"); |
| assertNotNull(intProperty, "intProperty exists"); |
| assertInstanceOf(Integer.class, intProperty, "intProperty type"); |
| assertEquals(103, ((Integer) intProperty).intValue(), "intProperty value"); |
| |
| final Object nullProperty = row.get("nullProperty"); |
| assertNull(nullProperty, "nullProperty null"); |
| |
| final Object stringProperty = row.get("stringProperty"); |
| assertNotNull(stringProperty, "stringProperty exists"); |
| assertInstanceOf(String.class, stringProperty, "stringProperty type"); |
| assertEquals("This is a string", (String) stringProperty, "stringProperty value"); |
| |
| } |
| |
| @Test |
| void testNewInstance() { |
| assertThrows(UnsupportedOperationException.class, () -> dynaClass.newInstance()); |
| } |
| } |