/** * 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.metamodel.data; import java.io.ObjectInputStream; import java.io.ObjectInputStream.GetField; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; import org.apache.metamodel.query.SelectItem; /** * Default Row implementation. Holds values in memory. */ public final class DefaultRow extends AbstractRow implements Row { private static final long serialVersionUID = 1L; private final DataSetHeader _header; private final Object[] _values; private final Style[] _styles; /** * Constructs a row. * * @param header * @param values * @param styles */ public DefaultRow(DataSetHeader header, Object[] values, Style[] styles) { if (header == null) { throw new IllegalArgumentException("DataSet header cannot be null"); } if (values == null) { throw new IllegalArgumentException("Values cannot be null"); } if (header.size() != values.length) { throw new IllegalArgumentException("Header size and values length must be equal. " + header.size() + " select items present in header and encountered these values: " + Arrays.toString(values)); } if (styles != null) { if (values.length != styles.length) { throw new IllegalArgumentException("Values length and styles length must be equal. " + values.length + " values present and encountered these styles: " + Arrays.toString(styles)); } boolean entirelyNoStyle = true; for (int i = 0; i < styles.length; i++) { if (styles[i] == null) { throw new IllegalArgumentException("Elements in the style array cannot be null"); } if (entirelyNoStyle && !Style.NO_STYLE.equals(styles[i])) { entirelyNoStyle = false; } } if (entirelyNoStyle) { // no need to reference any styles styles = null; } } _header = header; _values = values; _styles = styles; } /** * Constructs a row. * * @param header * @param values */ public DefaultRow(DataSetHeader header, Object[] values) { this(header, values, null); } /** * Constructs a row from an array of SelectItems and an array of * corresponding values * * @param items * the array of SelectItems * @param values * the array of values * * @deprecated use {@link #DefaultRow(DataSetHeader, Object[])} or * {@link #DefaultRow(DataSetHeader, Object[], Style[])} * instead. */ @Deprecated public DefaultRow(SelectItem[] items, Object[] values) { this(Arrays.asList(items), values, null); } /** * Constructs a row from an array of SelectItems and an array of * corresponding values * * @param items * the array of SelectItems * @param values * the array of values * @param styles * an optional array of styles * @deprecated use {@link #DefaultRow(DataSetHeader, Object[])} or * {@link #DefaultRow(DataSetHeader, Object[], Style[])} * instead. */ @Deprecated public DefaultRow(SelectItem[] items, Object[] values, Style[] styles) { this(Arrays.asList(items), values, styles); } /** * Constructs a row from a list of SelectItems and an array of corresponding * values * * @param items * the list of SelectItems * @param values * the array of values * @deprecated use {@link #DefaultRow(DataSetHeader, Object[])} or * {@link #DefaultRow(DataSetHeader, Object[], Style[])} * instead. */ @Deprecated public DefaultRow(List<SelectItem> items, Object[] values) { this(items, values, null); } /** * Constructs a row from a list of SelectItems and an array of corresponding * values * * @param items * the list of SelectItems * @param values * the array of values * @param styles * an optional array of styles * @deprecated use {@link #DefaultRow(DataSetHeader, Object[])} or * {@link #DefaultRow(DataSetHeader, Object[], Style[])} * instead. */ @Deprecated public DefaultRow(List<SelectItem> items, Object[] values, Style[] styles) { this(new SimpleDataSetHeader(items), values, styles); } @Override public Object getValue(int index) throws ArrayIndexOutOfBoundsException { return _values[index]; } @Override public Object[] getValues() { return _values; } @Override public Style getStyle(int index) throws IndexOutOfBoundsException { if (_styles == null) { return Style.NO_STYLE; } return _styles[index]; } @Override public Style[] getStyles() { return _styles; } @Override protected DataSetHeader getHeader() { return _header; } /** * Method invoked by the Java serialization framework while deserializing * Row instances. Since previous versions of MetaModel did not use a * DataSetHeader, but had a reference to a List<SelectItem>, this * deserialization is particularly tricky. We check if the items variable is * there, and if it is, we convert it to a header instead. * * @param stream * @throws Exception */ private void readObject(ObjectInputStream stream) throws Exception { GetField fields = stream.readFields(); try { // backwards compatible deserialization, convert items to header Object items = fields.get("_items", null); @SuppressWarnings("unchecked") List<SelectItem> itemsList = (List<SelectItem>) items; SimpleDataSetHeader header = new SimpleDataSetHeader(itemsList); Field field = getClass().getDeclaredField("_header"); field.setAccessible(true); field.set(this, header); } catch (IllegalArgumentException e) { // no backwards compatible deserialization needed. setWhileDeserializing(fields, "_header"); } setWhileDeserializing(fields, "_values"); setWhileDeserializing(fields, "_styles"); } private void setWhileDeserializing(GetField fields, String fieldName) throws Exception { Object value = fields.get(fieldName, null); Field field = getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(this, value); } }