001package jmri.util; 002import java.util.ArrayList; 003import java.util.Collection; 004 005import javax.annotation.Nonnull; 006 007/** 008 * An ArrayList that SpotBugs understands will never contain null elements. 009 * 010 * @see java.util.ArrayList 011 * @see java.util.List 012 * @author Bob Jacobsen, Copyright (C) 2017 013 * @param <E> E 014 */ 015public class NonNullArrayList<E> extends ArrayList<E> { 016 017 @Override 018 public boolean add(E e) { 019 if (e == null) throw new IllegalArgumentException("NonNullArrayList.addAll cannot add null item"); 020 return super.add(e); 021 } 022 023 @Override 024 public void add(int i, E e) { 025 if (e == null) throw new IllegalArgumentException("NonNullArrayList.addAll cannot add null item"); 026 super.add(i, e); 027 } 028 029 @Override 030 public boolean addAll(Collection<? extends E> c) { // ideally, would be "extends @Nonnull e", but that's not this annotation 031 for (E e : c ) { 032 if (e == null) throw new IllegalArgumentException("NonNullArrayList.addAll cannot accept collection containing null"); 033 } 034 return super.addAll(c); 035 } 036 037 @Override 038 public boolean addAll(int i, Collection<? extends E> c) { // ideally, would be "extends @Nonnull e", but that's not this annotation 039 for (E e : c ) { 040 if (e == null) throw new IllegalArgumentException("NonNullArrayList.addAll cannot accept collection containing null"); 041 } 042 return super.addAll(i, c); 043 } 044 045 @Override 046 @Nonnull 047 public E get(int i) { return super.get(i); } 048 049 @Override 050 @Nonnull 051 public E remove(int i) { return super.remove(i); } 052 053 @Override 054 @Nonnull 055 public E set(int i, E e) { 056 if (e == null) throw new IllegalArgumentException("NonNullArrayList.addAll cannot set item null"); 057 return super.set(i, e); 058 } 059 060 // test routines for SpotBugs checking - protected so you don't see them 061 // These should be clean 062 protected NonNullArrayList<Integer> testAddAndReturn() { 063 NonNullArrayList<Integer> t = new NonNullArrayList<>(); 064 t.add(100); 065 // t.add(null); // SpotBugs will tag this 066 return t; 067 } 068 069 protected boolean testLoop(String c) { 070 NonNullArrayList<Integer> t = new NonNullArrayList<>(); 071 t.add(100); 072 for (Integer s : t) { 073 if (s.toString().equals(c)) return true; // SpotBugs should not require null check 074 } 075 return false; 076 } 077 078 protected boolean asArgumentCheck(NonNullArrayList<Integer> t) { 079 if (t.get(0).toString().equals("100")) return true; // dereference of element of unknown Collection 080 for (Integer s : t) { 081 if (s.toString().equals("123")) return true; // dereference of element of unknown Collection 082 } 083 return false; 084 } 085 086 087}