All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.util.AutoPopulatingList Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed 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.springframework.util;

import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * Simple {@link List} wrapper class that allows for elements to be
 * automatically populated as they are requested. This is particularly
 * useful for data binding to {@link List Lists}, allowing for elements
 * to be created and added to the {@link List} in a "just in time" fashion.
 *
 * 

Note: This class is not thread-safe. To create a thread-safe version, * use the {@link java.util.Collections#synchronizedList} utility methods. * *

Inspired by {@code LazyList} from Commons Collections. * * @author Rob Harrop * @author Juergen Hoeller * @since 2.0 */ @SuppressWarnings("serial") public class AutoPopulatingList implements List, Serializable { /** * The {@link List} that all operations are eventually delegated to. */ private final List backingList; /** * The {@link ElementFactory} to use to create new {@link List} elements * on demand. */ private final ElementFactory elementFactory; /** * Creates a new {@code AutoPopulatingList} that is backed by a standard * {@link ArrayList} and adds new instances of the supplied {@link Class element Class} * to the backing {@link List} on demand. */ public AutoPopulatingList(Class elementClass) { this(new ArrayList(), elementClass); } /** * Creates a new {@code AutoPopulatingList} that is backed by the supplied {@link List} * and adds new instances of the supplied {@link Class element Class} to the backing * {@link List} on demand. */ public AutoPopulatingList(List backingList, Class elementClass) { this(backingList, new ReflectiveElementFactory(elementClass)); } /** * Creates a new {@code AutoPopulatingList} that is backed by a standard * {@link ArrayList} and creates new elements on demand using the supplied {@link ElementFactory}. */ public AutoPopulatingList(ElementFactory elementFactory) { this(new ArrayList(), elementFactory); } /** * Creates a new {@code AutoPopulatingList} that is backed by the supplied {@link List} * and creates new elements on demand using the supplied {@link ElementFactory}. */ public AutoPopulatingList(List backingList, ElementFactory elementFactory) { Assert.notNull(backingList, "Backing List must not be null"); Assert.notNull(elementFactory, "Element factory must not be null"); this.backingList = backingList; this.elementFactory = elementFactory; } @Override public void add(int index, E element) { this.backingList.add(index, element); } @Override public boolean add(E o) { return this.backingList.add(o); } @Override public boolean addAll(Collection c) { return this.backingList.addAll(c); } @Override public boolean addAll(int index, Collection c) { return this.backingList.addAll(index, c); } @Override public void clear() { this.backingList.clear(); } @Override public boolean contains(Object o) { return this.backingList.contains(o); } @Override public boolean containsAll(Collection c) { return this.backingList.containsAll(c); } /** * Get the element at the supplied index, creating it if there is * no element at that index. */ @Override public E get(int index) { int backingListSize = this.backingList.size(); E element = null; if (index < backingListSize) { element = this.backingList.get(index); if (element == null) { element = this.elementFactory.createElement(index); this.backingList.set(index, element); } } else { for (int x = backingListSize; x < index; x++) { this.backingList.add(null); } element = this.elementFactory.createElement(index); this.backingList.add(element); } return element; } @Override public int indexOf(Object o) { return this.backingList.indexOf(o); } @Override public boolean isEmpty() { return this.backingList.isEmpty(); } @Override public Iterator iterator() { return this.backingList.iterator(); } @Override public int lastIndexOf(Object o) { return this.backingList.lastIndexOf(o); } @Override public ListIterator listIterator() { return this.backingList.listIterator(); } @Override public ListIterator listIterator(int index) { return this.backingList.listIterator(index); } @Override public E remove(int index) { return this.backingList.remove(index); } @Override public boolean remove(Object o) { return this.backingList.remove(o); } @Override public boolean removeAll(Collection c) { return this.backingList.removeAll(c); } @Override public boolean retainAll(Collection c) { return this.backingList.retainAll(c); } @Override public E set(int index, E element) { return this.backingList.set(index, element); } @Override public int size() { return this.backingList.size(); } @Override public List subList(int fromIndex, int toIndex) { return this.backingList.subList(fromIndex, toIndex); } @Override public Object[] toArray() { return this.backingList.toArray(); } @Override public T[] toArray(T[] a) { return this.backingList.toArray(a); } @Override public boolean equals(Object other) { return this.backingList.equals(other); } @Override public int hashCode() { return this.backingList.hashCode(); } /** * Factory interface for creating elements for an index-based access * data structure such as a {@link java.util.List}. */ public interface ElementFactory { /** * Create the element for the supplied index. * @return the element object * @throws ElementInstantiationException if the instantiation process failed * (any exception thrown by a target constructor should be propagated as-is) */ E createElement(int index) throws ElementInstantiationException; } /** * Exception to be thrown from ElementFactory. */ public static class ElementInstantiationException extends RuntimeException { public ElementInstantiationException(String msg) { super(msg); } public ElementInstantiationException(String message, Throwable cause) { super(message, cause); } } /** * Reflective implementation of the ElementFactory interface, * using {@code Class.newInstance()} on a given element class. */ private static class ReflectiveElementFactory implements ElementFactory, Serializable { private final Class elementClass; public ReflectiveElementFactory(Class elementClass) { Assert.notNull(elementClass, "Element class must not be null"); Assert.isTrue(!elementClass.isInterface(), "Element class must not be an interface type"); Assert.isTrue(!Modifier.isAbstract(elementClass.getModifiers()), "Element class cannot be an abstract class"); this.elementClass = elementClass; } @Override public E createElement(int index) { try { return this.elementClass.newInstance(); } catch (InstantiationException ex) { throw new ElementInstantiationException( "Unable to instantiate element class: " + this.elementClass.getName(), ex); } catch (IllegalAccessException ex) { throw new ElementInstantiationException( "Could not access element constructor: " + this.elementClass.getName(), ex); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy