# NetBeans IDE HG Patch # This patch file was generated by NetBeans IDE # Following Index: paths are relative to: /home/matthias/nb-sources/core-main # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/JPQLEditorTopComponent.java --- j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/JPQLEditorTopComponent.java +++ j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/JPQLEditorTopComponent.java @@ -53,20 +53,17 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; +import java.beans.IntrospectionException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.StringTokenizer; -import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.DefaultComboBoxModel; @@ -77,16 +74,13 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableModel; import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; -import org.netbeans.api.db.explorer.JDBCDriver; -import org.netbeans.api.db.explorer.JDBCDriverManager; -import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; -import org.netbeans.api.project.libraries.Library; import org.netbeans.modules.editor.NbEditorDocument; import org.netbeans.modules.j2ee.persistence.api.PersistenceEnvironment; import org.netbeans.modules.j2ee.persistence.dd.common.Persistence; @@ -100,8 +94,6 @@ import org.netbeans.modules.j2ee.persistence.provider.ProviderUtil; import org.netbeans.modules.j2ee.persistence.unit.PUDataObject; import org.netbeans.modules.j2ee.persistence.wizard.Util; -import org.netbeans.modules.j2ee.persistence.wizard.jpacontroller.JpaControllerUtil; -import org.netbeans.modules.j2ee.persistence.wizard.library.PersistenceLibrarySupport; import org.openide.awt.MouseUtils.PopupMouseAdapter; import org.openide.filesystems.FileObject; import org.openide.filesystems.MIMEResolver; @@ -182,6 +174,7 @@ }); jpqlEditor.addMouseListener(new JPQLEditorPopupMouseAdapter()); showSQL(NbBundle.getMessage(JPQLEditorTopComponent.class, "BuildHint")); + resultsTable.setDefaultRenderer(Object.class, new NullTableCellRenderer()); } private class JPQLEditorPopupMouseAdapter extends PopupMouseAdapter { @@ -538,35 +531,18 @@ setStatus(strBuffer.toString()); - Vector tableHeaders = new Vector(); - Vector tableData = new Vector(); + TableModel tm = new DefaultTableModel(); if (!result.getQueryResults().isEmpty()) { - - Object firstObject = result.getQueryResults().get(0); - if (firstObject instanceof Object[]) { - // Join query result. - for (Object oneObject : (Object[]) firstObject) { - createTableHeaders(tableHeaders, oneObject); + try { + List info = ReflectionInfo.prepare(result.getQueryResults()); + tm = new ReflectiveTableModel(info, result.getQueryResults()); + } catch (IntrospectionException ex) { + logger.log(Level.WARNING, "Failed to reflect while building table model for JPA display", ex); } - - for (Object row : result.getQueryResults()) { - createTableData(tableData, (Object[]) row); } - - } else { - // Construct the table headers - createTableHeaders(tableHeaders, firstObject); - for (Object oneObject : result.getQueryResults()) { - createTableData(tableData, oneObject); - } - } - - } else { - - } resultsTable.clearSelection(); - resultsTable.setModel(new JPQLEditorResultTableModel(tableData, tableHeaders)); //new DefaultTableModel(tableData, tableHeaders)); + resultsTable.setModel(tm); } else { @@ -596,90 +572,10 @@ Thread.currentThread().setContextClassLoader(oldClassLoader); } - private void createTableHeaders(Vector tableHeaders, Object oneObject) { - if (oneObject == null || oneObject.getClass().getName().startsWith("java.lang") || oneObject.getClass().getName().startsWith("java.math")) {//NOI18N - //case for Long, String etc - tableHeaders.add(org.openide.util.NbBundle.getMessage(JPQLEditorTopComponent.class, "queryResultDefaultColumnName") + " " + (tableHeaders.size() + 1));//NOI18N - } else { - for (java.lang.reflect.Method m : oneObject.getClass().getDeclaredMethods()) { - String methodName = m.getName(); - if (methodName.startsWith("get")) { //NOI18N - String head = JpaControllerUtil.getPropNameFromMethod(methodName); - try { - oneObject.getClass().getDeclaredField(head); - tableHeaders.add(head); - } catch (Exception ex) { - String head2 = null; - for(Field f:oneObject.getClass().getDeclaredFields()){ - if(head.equalsIgnoreCase(f.getName())){ - head2 = head; - } - } - head2 = head2 == null ? methodName.substring(3) : head2; - tableHeaders.add(head2); - } - - } - } - } - } - - private void createTableData(Vector tableData, Object... rowObject) { - Vector oneRow = new Vector(); - for (Object oneObject : rowObject) { - if (oneObject == null) { - oneRow.add("NULL");//NOI18N - } else if (oneObject.getClass().getName().startsWith("java.lang") || oneObject.getClass().getName().startsWith("java.math")) { - //case for Long, String etc - oneRow.add(oneObject.toString()); - } else { - for (java.lang.reflect.Method m : oneObject.getClass().getDeclaredMethods()) { - String methodName = m.getName(); - if (methodName.startsWith("get")) { //NOI18N - try { - Object methodReturnValue = m.invoke(oneObject, new Object[]{}); - if (methodReturnValue == null) { - oneRow.add("NULL"); //NOI18N - continue; - } - if (methodReturnValue instanceof java.util.Collection) { - oneRow.add(methodReturnValue.toString()); - continue; - } - oneRow.add(methodReturnValue.toString()); - } catch (IllegalAccessException ex) { - //Exceptions.printStackTrace(ex); - } catch (IllegalArgumentException ex) { - //Exceptions.printStackTrace(ex); - } catch (InvocationTargetException ex) { - Exceptions.printStackTrace(ex); - } - } - } - } - } - tableData.add(oneRow); - } - private void setStatus(String message) { statusLabel.setText(message); } - /* - * Creates custom table model with read only cell customization. - */ - private class JPQLEditorResultTableModel extends DefaultTableModel { - - public JPQLEditorResultTableModel(Vector tableData, Vector tableHeaders) { - super(tableData, tableHeaders); - } - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - } - private String removePersistenceModuleCodelines(String exceptionTrace) { StringTokenizer tokenizer = new StringTokenizer(exceptionTrace, "\n"); StringBuilder filteredExceptionTrace = new StringBuilder(); Index: j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/NullTableCellRenderer.java --- j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/NullTableCellRenderer.java +++ j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/NullTableCellRenderer.java @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.j2ee.persistence.jpqleditor.ui; + +import java.awt.Component; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +public class NullTableCellRenderer extends DefaultTableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if(value == null) { + value = ""; + } + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + +} Index: j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectionInfo.java --- j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectionInfo.java +++ j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectionInfo.java @@ -0,0 +1,144 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.j2ee.persistence.jpqleditor.ui; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.TreeSet; + +public class ReflectionInfo implements Comparable { + private final Integer index; + private final String propertyName; + + private ReflectionInfo(Integer index, String propertyName) { + this.index = index; + this.propertyName = propertyName; + } + + public Integer getIndex() { + return index; + } + + public String getPropertyName() { + return propertyName; + } + + @Override + public String toString() { + return "{" + index + ", " + propertyName + '}'; + } + + + @Override + public int compareTo(ReflectionInfo o) { + int val1 = (index == null ? 0 : index); + int val2 = (o.index == null ? 0 : o.index); + int result = val1 - val2; + if(result != 0) { + return result; + } + String string1 = (propertyName == null ? "" : propertyName); + String string2 = (o.propertyName == null ? "" : o.propertyName); + return string1.compareToIgnoreCase(string2); + } + + public static List prepare (List data) throws IntrospectionException { + // Array mode is followed, if each data item is an array and has same dimension + Integer rowLength = null; + for(Object row: data) { + if(row instanceof Object[]) { + if(rowLength != null) { + // Arraylength differs + if(rowLength != ((Object[]) row).length) { + rowLength = null; + break; + } + } else { + // Initial row length + rowLength = ((Object[]) row).length; + } + } else { + // Non array + rowLength = null; + break; + } + } + + TreeSet resultPrecursor = new TreeSet<>(); + for (Object row : data) { + if (rowLength != null) { + Object[] rowArray = (Object[]) row; + for (int i = 0; i < rowLength; i++) { + resultPrecursor.addAll(fromObject(i, rowArray[i])); + } + } else { + resultPrecursor.addAll(fromObject(null, row)); + } + + } + + return new ArrayList<>(resultPrecursor); + } + + private static List fromObject(Integer index, Object obj) throws IntrospectionException { + if(obj == null || obj.getClass().getName().startsWith("java.")) { + // Let the default handle this + return Collections.singletonList(new ReflectionInfo(index, null)); + } else { + BeanInfo bi = Introspector.getBeanInfo(obj.getClass(), Object.class); + List result = new ArrayList<>(); + for(PropertyDescriptor pd: bi.getPropertyDescriptors()) { + result.add(new ReflectionInfo(index, pd.getName())); + } + if(result.isEmpty()) { + return Collections.singletonList(new ReflectionInfo(index, null)); + } else { + return result; + } + } + } +} Index: j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectiveTableModel.java --- j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectiveTableModel.java +++ j2ee.persistence/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectiveTableModel.java @@ -0,0 +1,126 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.j2ee.persistence.jpqleditor.ui; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.table.AbstractTableModel; + +public class ReflectiveTableModel extends AbstractTableModel { + + private static final Logger LOG = Logger.getLogger(ReflectiveTableModel.class.getName()); + + private List reflectionInfo; + private List data; + + public ReflectiveTableModel(List reflectionInfo, List data) { + if(data == null) { + throw new IllegalArgumentException("Data must not be null"); //NOI18N + } + this.reflectionInfo = reflectionInfo; + this.data = data; + } + + @Override + public String getColumnName(int columnIndex) { + ReflectionInfo ri = reflectionInfo.get(columnIndex); + if(ri.getIndex() == null && ri.getPropertyName() == null) { + return "Result"; + } else if (ri.getIndex() != null && ri.getPropertyName() == null) { + return "[" + ri.getIndex() + "]"; + } else if (ri.getIndex() == null && ri.getPropertyName() != null) { + return ri.getPropertyName(); + } else { + return "[" + ri.getIndex() + "]." + ri.getPropertyName(); + } + } + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return reflectionInfo.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object dataItem = data.get(rowIndex); + if(dataItem == null) { + return null; + } + ReflectionInfo ri = reflectionInfo.get(columnIndex); + if(ri.getIndex() != null) { + dataItem = ((Object[]) dataItem)[ri.getIndex()]; + } + if(dataItem == null || ri.getPropertyName() == null) { + return dataItem; + } + Class klass = dataItem.getClass(); + String property = ri.getPropertyName(); + Method accessor = null; + String getterString = "get" + property.substring(0, 1).toUpperCase() + property.substring(1); + String isString = "is" + property.substring(0, 1).toUpperCase() + property.substring(1); + try { + Method getter = klass.getMethod(getterString); + return getter.invoke(dataItem); + } catch (NoSuchMethodException ex) { + } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + LOG.log(Level.WARNING, "Failed to reflect", ex); //NOI18N + return null; + } + try { + Method getter = klass.getMethod(isString); + return getter.invoke(dataItem); + } catch (NoSuchMethodException ex) { + } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + LOG.log(Level.WARNING, "Failed to reflect", ex); //NOI18N + return null; + } + return null; + } +} Index: j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectionInfoTest.java --- j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectionInfoTest.java +++ j2ee.persistence/test/unit/src/org/netbeans/modules/j2ee/persistence/jpqleditor/ui/ReflectionInfoTest.java @@ -0,0 +1,215 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.j2ee.persistence.jpqleditor.ui; + +import java.beans.IntrospectionException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; + +public class ReflectionInfoTest { + + public ReflectionInfoTest() { + } + + @Test + public void testSingleResult() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Collections.singletonList(1)); + assertThat(ri.size(), is(1)); + assertNull(ri.get(0).getIndex()); + assertNull(ri.get(0).getPropertyName()); + } + + @Test + public void testSimpleObject() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Collections.singletonList(new BaseObject())); + assertThat(ri.size(), is(1)); + assertNull(ri.get(0).getIndex()); + assertThat(ri.get(0).getPropertyName(), is("id")); + } + + @Test + public void testInheritetObject() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Collections.singletonList(new DemoObject())); + assertThat(ri.size(), is(3)); + assertNull(ri.get(0).getIndex()); + assertThat(ri.get(0).getPropertyName(), is("demoBool")); + assertNull(ri.get(1).getIndex()); + assertThat(ri.get(1).getPropertyName(), is("id")); + assertNull(ri.get(2).getIndex()); + assertThat(ri.get(2).getPropertyName(), is("title")); + } + + @Test + public void testMixedList() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Arrays.asList(new BaseObject[]{new DemoObject2(), new DemoObject()})); + assertThat(ri.size(), is(4)); + assertNull(ri.get(0).getIndex()); + assertThat(ri.get(0).getPropertyName(), is("demoBool")); + assertNull(ri.get(1).getIndex()); + assertThat(ri.get(1).getPropertyName(), is("id")); + assertNull(ri.get(2).getIndex()); + assertThat(ri.get(2).getPropertyName(), is("title")); + assertNull(ri.get(3).getIndex()); + assertThat(ri.get(3).getPropertyName(), is("titleId")); + } + + @Test + public void testMixedRowArray() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Collections.singletonList(new Object[]{1, new DemoObject()})); + assertThat(ri.size(), is(4)); + assertThat(ri.get(0).getIndex(), is(0)); + assertNull(ri.get(0).getPropertyName()); + assertThat(ri.get(1).getIndex(), is(1)); + assertThat(ri.get(1).getPropertyName(), is("demoBool")); + assertThat(ri.get(2).getIndex(), is(1)); + assertThat(ri.get(2).getPropertyName(), is("id")); + assertThat(ri.get(3).getIndex(), is(1)); + assertThat(ri.get(3).getPropertyName(), is("title")); + } + + @Test + public void testNullRowLeadsToNonArray() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Arrays.asList( + new Object[]{1, new DemoObject()}, + null, + new Object[]{2, new DemoObject2()} + )); + assertThat(ri.size(), is(1)); + assertNull(ri.get(0).getPropertyName()); + assertNull(ri.get(0).getIndex()); + } + + @Test + public void testNullValues() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Arrays.asList( + null, + null, + null + )); + assertThat(ri.size(), is(1)); + assertNull(ri.get(0).getPropertyName()); + assertNull(ri.get(0).getIndex()); + } + + @Test + public void testNullValueArrays() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Arrays.asList( + new Object[] {null, null}, + new Object[] {null, null}, + new Object[] {null, null} + )); + assertThat(ri.size(), is(2)); + assertNull(ri.get(0).getPropertyName()); + assertThat(ri.get(0).getIndex(), is(0)); + assertNull(ri.get(1).getPropertyName()); + assertThat(ri.get(1).getIndex(), is(1)); + } + + @Test + public void testPartitialNullValueArrays() throws IntrospectionException { + List ri = ReflectionInfo.prepare(Arrays.asList( + new Object[] {null, null}, + new Object[] {1, new BaseObject()}, + new Object[] {null, null} + )); + assertThat(ri.size(), is(3)); + assertNull(ri.get(0).getPropertyName()); + assertThat(ri.get(0).getIndex(), is(0)); + assertNull(ri.get(1).getPropertyName()); + assertThat(ri.get(1).getIndex(), is(1)); + assertThat(ri.get(2).getPropertyName(), is("id")); + assertThat(ri.get(2).getIndex(), is(1)); + } + + public static class BaseObject { + + private int id; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + } + + public static class DemoObject2 extends BaseObject { + + private int titleId; + + public int getTitleId() { + return titleId; + } + + public void setTitleId(int titleId) { + this.titleId = titleId; + } + + } + + public static class DemoObject extends BaseObject { + + private String title; + private boolean demoBool; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isDemoBool() { + return demoBool; + } + + public void setDemoBool(boolean demoBool) { + this.demoBool = demoBool; + } + } +}