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