Mega Code Archive

 
Categories / Java / Generics
 

Create a typesafe view over an underlying raw set

/*  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.  *  * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.  *  * 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.  Sun designates this  * particular file as subject to the "Classpath" exception as provided  * by Sun 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]"  *  * Contributor(s):  *  * The Original Software is NetBeans. The Initial Developer of the Original  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun  * Microsystems, Inc. All Rights Reserved.  *  * 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.  */ import java.io.Serializable; import java.util.AbstractSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; /**  * @since 4.37  * @author Jaroslav Tulach  */ public class Utils {   /**    * Create a typesafe view over an underlying raw set.    * Mutations affect the underlying set (this is not a copy).    * {@link Set#clear} will make the view empty but may not clear the underlying set.    * You may add elements only of the requested type.    * {@link Set#contains} also performs a type check and will throw {@link ClassCastException}    * for an illegal argument.    * The view is serializable if the underlying set is.    * @param rawSet an unchecked set    * @param type the desired element type    * @param strict if false, elements in the underlying set which are not null and which are not assignable    *               to the requested type are omitted from the view;    *               if true, a {@link ClassCastException} may arise during some set operation    * @return a view over the raw set guaranteed to match the specified type    */   public static <E> Set<E> checkedSetByFilter(Set rawSet, Class<E> type, boolean strict) {       return new CheckedSet<E>(rawSet, type, strict);   }   private static final class CheckedSet<E> extends AbstractSet<E> implements Serializable {       private static final long serialVersionUID = 1L;       private final Set rawSet;       private final Class<E> type;       private final boolean strict;       public CheckedSet(Set rawSet, Class<E> type, boolean strict) {           this.rawSet = rawSet;           this.type = type;           this.strict = strict;       }       private boolean acceptEntry(Object o) {           if (o == null) {               return true;           } else if (type.isInstance(o)) {               return true;           } else if (strict) {               throw new ClassCastException(o + " was not a " + type.getName()); // NOI18N           } else {               return false;           }       }       @Override       public Iterator<E> iterator() {           return new CheckedIterator<E>(rawSet.iterator()) {               @Override               protected boolean accept(Object o) {                   return acceptEntry(o);               }           };       }       @Override       public int size() {           int c = 0;           Iterator it = rawSet.iterator();           while (it.hasNext()) {               if (acceptEntry(it.next())) {                   c++;               }           }           return c;       }       @Override       @SuppressWarnings("unchecked") // complains about usage of raw set       public boolean add(E o) {           return rawSet.add(type.cast(o));       }       @Override       public boolean contains(Object o) {           return rawSet.contains(type.cast(o));       }   } } abstract class CheckedIterator<E> implements Iterator<E> {   static final Object WAITING = new Object();   private final Iterator it;   private Object next = WAITING;   public CheckedIterator(Iterator it) {     this.it = it;   }   protected abstract boolean accept(Object o);   public boolean hasNext() {     if (next != WAITING) {       return true;     }     while (it.hasNext()) {       next = it.next();       if (accept(next)) {         return true;       }     }     next = WAITING;     return false;   }   public E next() {     if (next == WAITING && !hasNext()) {       throw new NoSuchElementException();     }     assert next != WAITING;     @SuppressWarnings("unchecked")     // type-checking is done by accept()     E x = (E) next;     next = WAITING;     return x;   }   public void remove() {     it.remove();   } }