# HG changeset patch # User Jaroslav Tulach # Date 1360049262 -3600 # Node ID 8338ab1991e6a7687233015f981072f969f2a60a # Parent 6b77554987e02b02e7f00e2a609533a97142b867# Parent 799a8cfefe35cef9617dbae745215964a083a6c9 Merging improved (inner) annotation support to allow its usage in emul branch diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/io/BufferedReader.java --- a/emul/compact/src/main/java/java/io/BufferedReader.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/io/BufferedReader.java Tue Feb 05 08:27:42 2013 +0100 @@ -25,7 +25,6 @@ package java.io; -import org.apidesign.bck2brwsr.emul.lang.System; /** diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/lang/AbstractMethodError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/main/java/java/lang/AbstractMethodError.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when an application tries to call an abstract method. + * Normally, this error is caught by the compiler; this error can + * only occur at run time if the definition of some class has + * incompatibly changed since the currently executing method was last + * compiled. + * + * @author unascribed + * @since JDK1.0 + */ +public +class AbstractMethodError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -1654391082989018462L; + + /** + * Constructs an AbstractMethodError with no detail message. + */ + public AbstractMethodError() { + super(); + } + + /** + * Constructs an AbstractMethodError with the specified + * detail message. + * + * @param s the detail message. + */ + public AbstractMethodError(String s) { + super(s); + } +} diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/lang/IncompatibleClassChangeError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/main/java/java/lang/IncompatibleClassChangeError.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when an incompatible class change has occurred to some class + * definition. The definition of some class, on which the currently + * executing method depends, has since changed. + * + * @author unascribed + * @since JDK1.0 + */ +public +class IncompatibleClassChangeError extends LinkageError { + private static final long serialVersionUID = -4914975503642802119L; + + /** + * Constructs an IncompatibleClassChangeError with no + * detail message. + */ + public IncompatibleClassChangeError () { + super(); + } + + /** + * Constructs an IncompatibleClassChangeError with the + * specified detail message. + * + * @param s the detail message. + */ + public IncompatibleClassChangeError(String s) { + super(s); + } +} diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/lang/NoSuchFieldError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/main/java/java/lang/NoSuchFieldError.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown if an application tries to access or modify a specified + * field of an object, and that object no longer has that field. + *

+ * Normally, this error is caught by the compiler; this error can + * only occur at run time if the definition of a class has + * incompatibly changed. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NoSuchFieldError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -3456430195886129035L; + + /** + * Constructs a NoSuchFieldError with no detail message. + */ + public NoSuchFieldError() { + super(); + } + + /** + * Constructs a NoSuchFieldError with the specified + * detail message. + * + * @param s the detail message. + */ + public NoSuchFieldError(String s) { + super(s); + } +} diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/lang/System.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/main/java/java/lang/System.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,36 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package java.lang; + +/** Poor man's re-implementation of most important System methods. + * + * @author Jaroslav Tulach + */ +public class System { + private System() { + } + + public static void arraycopy(Object value, int srcBegin, Object dst, int dstBegin, int count) { + org.apidesign.bck2brwsr.emul.lang.System.arraycopy(value, srcBegin, dst, dstBegin, count); + } + + public static long currentTimeMillis() { + return org.apidesign.bck2brwsr.emul.lang.System.currentTimeMillis(); + } + +} diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/ArrayDeque.java --- a/emul/compact/src/main/java/java/util/ArrayDeque.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/ArrayDeque.java Tue Feb 05 08:27:42 2013 +0100 @@ -34,7 +34,6 @@ package java.util; import java.io.*; -import org.apidesign.bck2brwsr.emul.lang.System; /** * Resizable-array implementation of the {@link Deque} interface. Array diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/ArrayList.java --- a/emul/compact/src/main/java/java/util/ArrayList.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/ArrayList.java Tue Feb 05 08:27:42 2013 +0100 @@ -25,7 +25,6 @@ package java.util; -import org.apidesign.bck2brwsr.emul.lang.System; /** * Resizable-array implementation of the List interface. Implements diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/Arrays.java --- a/emul/compact/src/main/java/java/util/Arrays.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/Arrays.java Tue Feb 05 08:27:42 2013 +0100 @@ -26,7 +26,6 @@ package java.util; import java.lang.reflect.*; -import org.apidesign.bck2brwsr.emul.lang.System; /** * This class contains various methods for manipulating arrays (such as diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/Collections.java --- a/emul/compact/src/main/java/java/util/Collections.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/Collections.java Tue Feb 05 08:27:42 2013 +0100 @@ -27,7 +27,6 @@ import java.io.Serializable; import java.io.IOException; import java.lang.reflect.Array; -import org.apidesign.bck2brwsr.emul.lang.System; /** * This class consists exclusively of static methods that operate on or return diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/ComparableTimSort.java --- a/emul/compact/src/main/java/java/util/ComparableTimSort.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/ComparableTimSort.java Tue Feb 05 08:27:42 2013 +0100 @@ -25,7 +25,6 @@ package java.util; -import org.apidesign.bck2brwsr.emul.lang.System; /** * This is a near duplicate of {@link TimSort}, modified for use with diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/PriorityQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/main/java/java/util/PriorityQueue.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + + +/** + * An unbounded priority {@linkplain Queue queue} based on a priority heap. + * The elements of the priority queue are ordered according to their + * {@linkplain Comparable natural ordering}, or by a {@link Comparator} + * provided at queue construction time, depending on which constructor is + * used. A priority queue does not permit {@code null} elements. + * A priority queue relying on natural ordering also does not permit + * insertion of non-comparable objects (doing so may result in + * {@code ClassCastException}). + * + *

The head of this queue is the least element + * with respect to the specified ordering. If multiple elements are + * tied for least value, the head is one of those elements -- ties are + * broken arbitrarily. The queue retrieval operations {@code poll}, + * {@code remove}, {@code peek}, and {@code element} access the + * element at the head of the queue. + * + *

A priority queue is unbounded, but has an internal + * capacity governing the size of an array used to store the + * elements on the queue. It is always at least as large as the queue + * size. As elements are added to a priority queue, its capacity + * grows automatically. The details of the growth policy are not + * specified. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. The Iterator provided in method {@link + * #iterator()} is not guaranteed to traverse the elements of + * the priority queue in any particular order. If you need ordered + * traversal, consider using {@code Arrays.sort(pq.toArray())}. + * + *

Note that this implementation is not synchronized. + * Multiple threads should not access a {@code PriorityQueue} + * instance concurrently if any of the threads modifies the queue. + * Instead, use the thread-safe {@link + * java.util.concurrent.PriorityBlockingQueue} class. + * + *

Implementation note: this implementation provides + * O(log(n)) time for the enqueing and dequeing methods + * ({@code offer}, {@code poll}, {@code remove()} and {@code add}); + * linear time for the {@code remove(Object)} and {@code contains(Object)} + * methods; and constant time for the retrieval methods + * ({@code peek}, {@code element}, and {@code size}). + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @since 1.5 + * @author Josh Bloch, Doug Lea + * @param the type of elements held in this collection + */ +public class PriorityQueue extends AbstractQueue + implements java.io.Serializable { + + private static final long serialVersionUID = -7720805057305804111L; + + private static final int DEFAULT_INITIAL_CAPACITY = 11; + + /** + * Priority queue represented as a balanced binary heap: the two + * children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The + * priority queue is ordered by comparator, or by the elements' + * natural ordering, if comparator is null: For each node n in the + * heap and each descendant d of n, n <= d. The element with the + * lowest value is in queue[0], assuming the queue is nonempty. + */ + private transient Object[] queue; + + /** + * The number of elements in the priority queue. + */ + private int size = 0; + + /** + * The comparator, or null if priority queue uses elements' + * natural ordering. + */ + private final Comparator comparator; + + /** + * The number of times this priority queue has been + * structurally modified. See AbstractList for gory details. + */ + private transient int modCount = 0; + + /** + * Creates a {@code PriorityQueue} with the default initial + * capacity (11) that orders its elements according to their + * {@linkplain Comparable natural ordering}. + */ + public PriorityQueue() { + this(DEFAULT_INITIAL_CAPACITY, null); + } + + /** + * Creates a {@code PriorityQueue} with the specified initial + * capacity that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param initialCapacity the initial capacity for this priority queue + * @throws IllegalArgumentException if {@code initialCapacity} is less + * than 1 + */ + public PriorityQueue(int initialCapacity) { + this(initialCapacity, null); + } + + /** + * Creates a {@code PriorityQueue} with the specified initial capacity + * that orders its elements according to the specified comparator. + * + * @param initialCapacity the initial capacity for this priority queue + * @param comparator the comparator that will be used to order this + * priority queue. If {@code null}, the {@linkplain Comparable + * natural ordering} of the elements will be used. + * @throws IllegalArgumentException if {@code initialCapacity} is + * less than 1 + */ + public PriorityQueue(int initialCapacity, + Comparator comparator) { + // Note: This restriction of at least one is not actually needed, + // but continues for 1.5 compatibility + if (initialCapacity < 1) + throw new IllegalArgumentException(); + this.queue = new Object[initialCapacity]; + this.comparator = comparator; + } + + /** + * Creates a {@code PriorityQueue} containing the elements in the + * specified collection. If the specified collection is an instance of + * a {@link SortedSet} or is another {@code PriorityQueue}, this + * priority queue will be ordered according to the same ordering. + * Otherwise, this priority queue will be ordered according to the + * {@linkplain Comparable natural ordering} of its elements. + * + * @param c the collection whose elements are to be placed + * into this priority queue + * @throws ClassCastException if elements of the specified collection + * cannot be compared to one another according to the priority + * queue's ordering + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + @SuppressWarnings("unchecked") + public PriorityQueue(Collection c) { + if (c instanceof SortedSet) { + SortedSet ss = (SortedSet) c; + this.comparator = (Comparator) ss.comparator(); + initElementsFromCollection(ss); + } + else if (c instanceof PriorityQueue) { + PriorityQueue pq = (PriorityQueue) c; + this.comparator = (Comparator) pq.comparator(); + initFromPriorityQueue(pq); + } + else { + this.comparator = null; + initFromCollection(c); + } + } + + /** + * Creates a {@code PriorityQueue} containing the elements in the + * specified priority queue. This priority queue will be + * ordered according to the same ordering as the given priority + * queue. + * + * @param c the priority queue whose elements are to be placed + * into this priority queue + * @throws ClassCastException if elements of {@code c} cannot be + * compared to one another according to {@code c}'s + * ordering + * @throws NullPointerException if the specified priority queue or any + * of its elements are null + */ + @SuppressWarnings("unchecked") + public PriorityQueue(PriorityQueue c) { + this.comparator = (Comparator) c.comparator(); + initFromPriorityQueue(c); + } + + /** + * Creates a {@code PriorityQueue} containing the elements in the + * specified sorted set. This priority queue will be ordered + * according to the same ordering as the given sorted set. + * + * @param c the sorted set whose elements are to be placed + * into this priority queue + * @throws ClassCastException if elements of the specified sorted + * set cannot be compared to one another according to the + * sorted set's ordering + * @throws NullPointerException if the specified sorted set or any + * of its elements are null + */ + @SuppressWarnings("unchecked") + public PriorityQueue(SortedSet c) { + this.comparator = (Comparator) c.comparator(); + initElementsFromCollection(c); + } + + private void initFromPriorityQueue(PriorityQueue c) { + if (c.getClass() == PriorityQueue.class) { + this.queue = c.toArray(); + this.size = c.size(); + } else { + initFromCollection(c); + } + } + + private void initElementsFromCollection(Collection c) { + Object[] a = c.toArray(); + // If c.toArray incorrectly doesn't return Object[], copy it. + if (a.getClass() != Object[].class) + a = Arrays.copyOf(a, a.length, Object[].class); + int len = a.length; + if (len == 1 || this.comparator != null) + for (int i = 0; i < len; i++) + if (a[i] == null) + throw new NullPointerException(); + this.queue = a; + this.size = a.length; + } + + /** + * Initializes queue array with elements from the given Collection. + * + * @param c the collection + */ + private void initFromCollection(Collection c) { + initElementsFromCollection(c); + heapify(); + } + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * Increases the capacity of the array. + * + * @param minCapacity the desired minimum capacity + */ + private void grow(int minCapacity) { + int oldCapacity = queue.length; + // Double size if small; else grow by 50% + int newCapacity = oldCapacity + ((oldCapacity < 64) ? + (oldCapacity + 2) : + (oldCapacity >> 1)); + // overflow-conscious code + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); + queue = Arrays.copyOf(queue, newCapacity); + } + + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; + } + + /** + * Inserts the specified element into this priority queue. + * + * @return {@code true} (as specified by {@link Collection#add}) + * @throws ClassCastException if the specified element cannot be + * compared with elements currently in this priority queue + * according to the priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element into this priority queue. + * + * @return {@code true} (as specified by {@link Queue#offer}) + * @throws ClassCastException if the specified element cannot be + * compared with elements currently in this priority queue + * according to the priority queue's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + if (e == null) + throw new NullPointerException(); + modCount++; + int i = size; + if (i >= queue.length) + grow(i + 1); + size = i + 1; + if (i == 0) + queue[0] = e; + else + siftUp(i, e); + return true; + } + + public E peek() { + if (size == 0) + return null; + return (E) queue[0]; + } + + private int indexOf(Object o) { + if (o != null) { + for (int i = 0; i < size; i++) + if (o.equals(queue[i])) + return i; + } + return -1; + } + + /** + * Removes a single instance of the specified element from this queue, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queue contains one or more such + * elements. Returns {@code true} if and only if this queue contained + * the specified element (or equivalently, if this queue changed as a + * result of the call). + * + * @param o element to be removed from this queue, if present + * @return {@code true} if this queue changed as a result of the call + */ + public boolean remove(Object o) { + int i = indexOf(o); + if (i == -1) + return false; + else { + removeAt(i); + return true; + } + } + + /** + * Version of remove using reference equality, not equals. + * Needed by iterator.remove. + * + * @param o element to be removed from this queue, if present + * @return {@code true} if removed + */ + boolean removeEq(Object o) { + for (int i = 0; i < size; i++) { + if (o == queue[i]) { + removeAt(i); + return true; + } + } + return false; + } + + /** + * Returns {@code true} if this queue contains the specified element. + * More formally, returns {@code true} if and only if this queue contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queue + * @return {@code true} if this queue contains the specified element + */ + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + /** + * Returns an array containing all of the elements in this queue. + * The elements are in no particular order. + * + *

The returned array will be "safe" in that no references to it are + * maintained by this queue. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queue + */ + public Object[] toArray() { + return Arrays.copyOf(queue, size); + } + + /** + * Returns an array containing all of the elements in this queue; the + * runtime type of the returned array is that of the specified array. + * The returned array elements are in no particular order. + * If the queue fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this queue. + * + *

If the queue fits in the specified array with room to spare + * (i.e., the array has more elements than the queue), the element in + * the array immediately following the end of the collection is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose x is a queue known to contain only strings. + * The following code can be used to dump the queue into a newly + * allocated array of String: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that toArray(new Object[0]) is identical in function to + * toArray(). + * + * @param a the array into which the elements of the queue are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose. + * @return an array containing all of the elements in this queue + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queue + * @throws NullPointerException if the specified array is null + */ + public T[] toArray(T[] a) { + if (a.length < size) + // Make a new array of a's runtime type, but my contents: + return (T[]) Arrays.copyOf(queue, size, a.getClass()); + System.arraycopy(queue, 0, a, 0, size); + if (a.length > size) + a[size] = null; + return a; + } + + /** + * Returns an iterator over the elements in this queue. The iterator + * does not return the elements in any particular order. + * + * @return an iterator over the elements in this queue + */ + public Iterator iterator() { + return new Itr(); + } + + private final class Itr implements Iterator { + /** + * Index (into queue array) of element to be returned by + * subsequent call to next. + */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next, + * unless that element came from the forgetMeNot list. + * Set to -1 if element is deleted by a call to remove. + */ + private int lastRet = -1; + + /** + * A queue of elements that were moved from the unvisited portion of + * the heap into the visited portion as a result of "unlucky" element + * removals during the iteration. (Unlucky element removals are those + * that require a siftup instead of a siftdown.) We must visit all of + * the elements in this list to complete the iteration. We do this + * after we've completed the "normal" iteration. + * + * We expect that most iterations, even those involving removals, + * will not need to store elements in this field. + */ + private ArrayDeque forgetMeNot = null; + + /** + * Element returned by the most recent call to next iff that + * element was drawn from the forgetMeNot list. + */ + private E lastRetElt = null; + + /** + * The modCount value that the iterator believes that the backing + * Queue should have. If this expectation is violated, the iterator + * has detected concurrent modification. + */ + private int expectedModCount = modCount; + + public boolean hasNext() { + return cursor < size || + (forgetMeNot != null && !forgetMeNot.isEmpty()); + } + + public E next() { + if (expectedModCount != modCount) + throw new ConcurrentModificationException(); + if (cursor < size) + return (E) queue[lastRet = cursor++]; + if (forgetMeNot != null) { + lastRet = -1; + lastRetElt = forgetMeNot.poll(); + if (lastRetElt != null) + return lastRetElt; + } + throw new NoSuchElementException(); + } + + public void remove() { + if (expectedModCount != modCount) + throw new ConcurrentModificationException(); + if (lastRet != -1) { + E moved = PriorityQueue.this.removeAt(lastRet); + lastRet = -1; + if (moved == null) + cursor--; + else { + if (forgetMeNot == null) + forgetMeNot = new ArrayDeque<>(); + forgetMeNot.add(moved); + } + } else if (lastRetElt != null) { + PriorityQueue.this.removeEq(lastRetElt); + lastRetElt = null; + } else { + throw new IllegalStateException(); + } + expectedModCount = modCount; + } + } + + public int size() { + return size; + } + + /** + * Removes all of the elements from this priority queue. + * The queue will be empty after this call returns. + */ + public void clear() { + modCount++; + for (int i = 0; i < size; i++) + queue[i] = null; + size = 0; + } + + public E poll() { + if (size == 0) + return null; + int s = --size; + modCount++; + E result = (E) queue[0]; + E x = (E) queue[s]; + queue[s] = null; + if (s != 0) + siftDown(0, x); + return result; + } + + /** + * Removes the ith element from queue. + * + * Normally this method leaves the elements at up to i-1, + * inclusive, untouched. Under these circumstances, it returns + * null. Occasionally, in order to maintain the heap invariant, + * it must swap a later element of the list with one earlier than + * i. Under these circumstances, this method returns the element + * that was previously at the end of the list and is now at some + * position before i. This fact is used by iterator.remove so as to + * avoid missing traversing elements. + */ + private E removeAt(int i) { + assert i >= 0 && i < size; + modCount++; + int s = --size; + if (s == i) // removed last element + queue[i] = null; + else { + E moved = (E) queue[s]; + queue[s] = null; + siftDown(i, moved); + if (queue[i] == moved) { + siftUp(i, moved); + if (queue[i] != moved) + return moved; + } + } + return null; + } + + /** + * Inserts item x at position k, maintaining heap invariant by + * promoting x up the tree until it is greater than or equal to + * its parent, or is the root. + * + * To simplify and speed up coercions and comparisons. the + * Comparable and Comparator versions are separated into different + * methods that are otherwise identical. (Similarly for siftDown.) + * + * @param k the position to fill + * @param x the item to insert + */ + private void siftUp(int k, E x) { + if (comparator != null) + siftUpUsingComparator(k, x); + else + siftUpComparable(k, x); + } + + private void siftUpComparable(int k, E x) { + Comparable key = (Comparable) x; + while (k > 0) { + int parent = (k - 1) >>> 1; + Object e = queue[parent]; + if (key.compareTo((E) e) >= 0) + break; + queue[k] = e; + k = parent; + } + queue[k] = key; + } + + private void siftUpUsingComparator(int k, E x) { + while (k > 0) { + int parent = (k - 1) >>> 1; + Object e = queue[parent]; + if (comparator.compare(x, (E) e) >= 0) + break; + queue[k] = e; + k = parent; + } + queue[k] = x; + } + + /** + * Inserts item x at position k, maintaining heap invariant by + * demoting x down the tree repeatedly until it is less than or + * equal to its children or is a leaf. + * + * @param k the position to fill + * @param x the item to insert + */ + private void siftDown(int k, E x) { + if (comparator != null) + siftDownUsingComparator(k, x); + else + siftDownComparable(k, x); + } + + private void siftDownComparable(int k, E x) { + Comparable key = (Comparable)x; + int half = size >>> 1; // loop while a non-leaf + while (k < half) { + int child = (k << 1) + 1; // assume left child is least + Object c = queue[child]; + int right = child + 1; + if (right < size && + ((Comparable) c).compareTo((E) queue[right]) > 0) + c = queue[child = right]; + if (key.compareTo((E) c) <= 0) + break; + queue[k] = c; + k = child; + } + queue[k] = key; + } + + private void siftDownUsingComparator(int k, E x) { + int half = size >>> 1; + while (k < half) { + int child = (k << 1) + 1; + Object c = queue[child]; + int right = child + 1; + if (right < size && + comparator.compare((E) c, (E) queue[right]) > 0) + c = queue[child = right]; + if (comparator.compare(x, (E) c) <= 0) + break; + queue[k] = c; + k = child; + } + queue[k] = x; + } + + /** + * Establishes the heap invariant (described above) in the entire tree, + * assuming nothing about the order of the elements prior to the call. + */ + private void heapify() { + for (int i = (size >>> 1) - 1; i >= 0; i--) + siftDown(i, (E) queue[i]); + } + + /** + * Returns the comparator used to order the elements in this + * queue, or {@code null} if this queue is sorted according to + * the {@linkplain Comparable natural ordering} of its elements. + * + * @return the comparator used to order this queue, or + * {@code null} if this queue is sorted according to the + * natural ordering of its elements + */ + public Comparator comparator() { + return comparator; + } + + +} diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/TimSort.java --- a/emul/compact/src/main/java/java/util/TimSort.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/TimSort.java Tue Feb 05 08:27:42 2013 +0100 @@ -25,7 +25,6 @@ package java.util; -import org.apidesign.bck2brwsr.emul.lang.System; /** * A stable, adaptive, iterative mergesort that requires far fewer than diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/Vector.java --- a/emul/compact/src/main/java/java/util/Vector.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/compact/src/main/java/java/util/Vector.java Tue Feb 05 08:27:42 2013 +0100 @@ -25,7 +25,6 @@ package java.util; -import org.apidesign.bck2brwsr.emul.lang.System; /** * The {@code Vector} class implements a growable array of diff -r 6b77554987e0 -r 8338ab1991e6 emul/compact/src/main/java/java/util/concurrent/TimeUnit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/compact/src/main/java/java/util/concurrent/TimeUnit.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,367 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent; + +/** + * A TimeUnit represents time durations at a given unit of + * granularity and provides utility methods to convert across units, + * and to perform timing and delay operations in these units. A + * TimeUnit does not maintain time information, but only + * helps organize and use time representations that may be maintained + * separately across various contexts. A nanosecond is defined as one + * thousandth of a microsecond, a microsecond as one thousandth of a + * millisecond, a millisecond as one thousandth of a second, a minute + * as sixty seconds, an hour as sixty minutes, and a day as twenty four + * hours. + * + *

A TimeUnit is mainly used to inform time-based methods + * how a given timing parameter should be interpreted. For example, + * the following code will timeout in 50 milliseconds if the {@link + * java.util.concurrent.locks.Lock lock} is not available: + * + *

  Lock lock = ...;
+ *  if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...
+ * 
+ * while this code will timeout in 50 seconds: + *
+ *  Lock lock = ...;
+ *  if (lock.tryLock(50L, TimeUnit.SECONDS)) ...
+ * 
+ * + * Note however, that there is no guarantee that a particular timeout + * implementation will be able to notice the passage of time at the + * same granularity as the given TimeUnit. + * + * @since 1.5 + * @author Doug Lea + */ +public enum TimeUnit { + NANOSECONDS { + public long toNanos(long d) { return d; } + public long toMicros(long d) { return d/(C1/C0); } + public long toMillis(long d) { return d/(C2/C0); } + public long toSeconds(long d) { return d/(C3/C0); } + public long toMinutes(long d) { return d/(C4/C0); } + public long toHours(long d) { return d/(C5/C0); } + public long toDays(long d) { return d/(C6/C0); } + public long convert(long d, TimeUnit u) { return u.toNanos(d); } + int excessNanos(long d, long m) { return (int)(d - (m*C2)); } + }, + MICROSECONDS { + public long toNanos(long d) { return x(d, C1/C0, MAX/(C1/C0)); } + public long toMicros(long d) { return d; } + public long toMillis(long d) { return d/(C2/C1); } + public long toSeconds(long d) { return d/(C3/C1); } + public long toMinutes(long d) { return d/(C4/C1); } + public long toHours(long d) { return d/(C5/C1); } + public long toDays(long d) { return d/(C6/C1); } + public long convert(long d, TimeUnit u) { return u.toMicros(d); } + int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); } + }, + MILLISECONDS { + public long toNanos(long d) { return x(d, C2/C0, MAX/(C2/C0)); } + public long toMicros(long d) { return x(d, C2/C1, MAX/(C2/C1)); } + public long toMillis(long d) { return d; } + public long toSeconds(long d) { return d/(C3/C2); } + public long toMinutes(long d) { return d/(C4/C2); } + public long toHours(long d) { return d/(C5/C2); } + public long toDays(long d) { return d/(C6/C2); } + public long convert(long d, TimeUnit u) { return u.toMillis(d); } + int excessNanos(long d, long m) { return 0; } + }, + SECONDS { + public long toNanos(long d) { return x(d, C3/C0, MAX/(C3/C0)); } + public long toMicros(long d) { return x(d, C3/C1, MAX/(C3/C1)); } + public long toMillis(long d) { return x(d, C3/C2, MAX/(C3/C2)); } + public long toSeconds(long d) { return d; } + public long toMinutes(long d) { return d/(C4/C3); } + public long toHours(long d) { return d/(C5/C3); } + public long toDays(long d) { return d/(C6/C3); } + public long convert(long d, TimeUnit u) { return u.toSeconds(d); } + int excessNanos(long d, long m) { return 0; } + }, + MINUTES { + public long toNanos(long d) { return x(d, C4/C0, MAX/(C4/C0)); } + public long toMicros(long d) { return x(d, C4/C1, MAX/(C4/C1)); } + public long toMillis(long d) { return x(d, C4/C2, MAX/(C4/C2)); } + public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); } + public long toMinutes(long d) { return d; } + public long toHours(long d) { return d/(C5/C4); } + public long toDays(long d) { return d/(C6/C4); } + public long convert(long d, TimeUnit u) { return u.toMinutes(d); } + int excessNanos(long d, long m) { return 0; } + }, + HOURS { + public long toNanos(long d) { return x(d, C5/C0, MAX/(C5/C0)); } + public long toMicros(long d) { return x(d, C5/C1, MAX/(C5/C1)); } + public long toMillis(long d) { return x(d, C5/C2, MAX/(C5/C2)); } + public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); } + public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); } + public long toHours(long d) { return d; } + public long toDays(long d) { return d/(C6/C5); } + public long convert(long d, TimeUnit u) { return u.toHours(d); } + int excessNanos(long d, long m) { return 0; } + }, + DAYS { + public long toNanos(long d) { return x(d, C6/C0, MAX/(C6/C0)); } + public long toMicros(long d) { return x(d, C6/C1, MAX/(C6/C1)); } + public long toMillis(long d) { return x(d, C6/C2, MAX/(C6/C2)); } + public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); } + public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); } + public long toHours(long d) { return x(d, C6/C5, MAX/(C6/C5)); } + public long toDays(long d) { return d; } + public long convert(long d, TimeUnit u) { return u.toDays(d); } + int excessNanos(long d, long m) { return 0; } + }; + + // Handy constants for conversion methods + static final long C0 = 1L; + static final long C1 = C0 * 1000L; + static final long C2 = C1 * 1000L; + static final long C3 = C2 * 1000L; + static final long C4 = C3 * 60L; + static final long C5 = C4 * 60L; + static final long C6 = C5 * 24L; + + static final long MAX = Long.MAX_VALUE; + + /** + * Scale d by m, checking for overflow. + * This has a short name to make above code more readable. + */ + static long x(long d, long m, long over) { + if (d > over) return Long.MAX_VALUE; + if (d < -over) return Long.MIN_VALUE; + return d * m; + } + + // To maintain full signature compatibility with 1.5, and to improve the + // clarity of the generated javadoc (see 6287639: Abstract methods in + // enum classes should not be listed as abstract), method convert + // etc. are not declared abstract but otherwise act as abstract methods. + + /** + * Convert the given time duration in the given unit to this + * unit. Conversions from finer to coarser granularities + * truncate, so lose precision. For example converting + * 999 milliseconds to seconds results in + * 0. Conversions from coarser to finer granularities + * with arguments that would numerically overflow saturate to + * Long.MIN_VALUE if negative or Long.MAX_VALUE + * if positive. + * + *

For example, to convert 10 minutes to milliseconds, use: + * TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES) + * + * @param sourceDuration the time duration in the given sourceUnit + * @param sourceUnit the unit of the sourceDuration argument + * @return the converted duration in this unit, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + */ + public long convert(long sourceDuration, TimeUnit sourceUnit) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to NANOSECONDS.convert(duration, this). + * @param duration the duration + * @return the converted duration, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + * @see #convert + */ + public long toNanos(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to MICROSECONDS.convert(duration, this). + * @param duration the duration + * @return the converted duration, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + * @see #convert + */ + public long toMicros(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to MILLISECONDS.convert(duration, this). + * @param duration the duration + * @return the converted duration, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + * @see #convert + */ + public long toMillis(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to SECONDS.convert(duration, this). + * @param duration the duration + * @return the converted duration, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + * @see #convert + */ + public long toSeconds(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to MINUTES.convert(duration, this). + * @param duration the duration + * @return the converted duration, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + * @see #convert + * @since 1.6 + */ + public long toMinutes(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to HOURS.convert(duration, this). + * @param duration the duration + * @return the converted duration, + * or Long.MIN_VALUE if conversion would negatively + * overflow, or Long.MAX_VALUE if it would positively overflow. + * @see #convert + * @since 1.6 + */ + public long toHours(long duration) { + throw new AbstractMethodError(); + } + + /** + * Equivalent to DAYS.convert(duration, this). + * @param duration the duration + * @return the converted duration + * @see #convert + * @since 1.6 + */ + public long toDays(long duration) { + throw new AbstractMethodError(); + } + + /** + * Utility to compute the excess-nanosecond argument to wait, + * sleep, join. + * @param d the duration + * @param m the number of milliseconds + * @return the number of nanoseconds + */ + abstract int excessNanos(long d, long m); + + /** + * Performs a timed {@link Object#wait(long, int) Object.wait} + * using this time unit. + * This is a convenience method that converts timeout arguments + * into the form required by the Object.wait method. + * + *

For example, you could implement a blocking poll + * method (see {@link BlockingQueue#poll BlockingQueue.poll}) + * using: + * + *

 {@code
+     * public synchronized Object poll(long timeout, TimeUnit unit)
+     *     throws InterruptedException {
+     *   while (empty) {
+     *     unit.timedWait(this, timeout);
+     *     ...
+     *   }
+     * }}
+ * + * @param obj the object to wait on + * @param timeout the maximum time to wait. If less than + * or equal to zero, do not wait at all. + * @throws InterruptedException if interrupted while waiting + */ + public void timedWait(Object obj, long timeout) + throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + obj.wait(ms, ns); + } + } + + /** + * Performs a timed {@link Thread#join(long, int) Thread.join} + * using this time unit. + * This is a convenience method that converts time arguments into the + * form required by the Thread.join method. + * + * @param thread the thread to wait for + * @param timeout the maximum time to wait. If less than + * or equal to zero, do not wait at all. + * @throws InterruptedException if interrupted while waiting + */ +// public void timedJoin(Thread thread, long timeout) +// throws InterruptedException { +// if (timeout > 0) { +// long ms = toMillis(timeout); +// int ns = excessNanos(timeout, ms); +// thread.join(ms, ns); +// } +// } + + /** + * Performs a {@link Thread#sleep(long, int) Thread.sleep} using + * this time unit. + * This is a convenience method that converts time arguments into the + * form required by the Thread.sleep method. + * + * @param timeout the minimum time to sleep. If less than + * or equal to zero, do not sleep at all. + * @throws InterruptedException if interrupted while sleeping + */ + public void sleep(long timeout) throws InterruptedException { + if (timeout > 0) { + long ms = toMillis(timeout); + int ns = excessNanos(timeout, ms); + Object o = new Object(); + synchronized (o) { + o.wait(ms, ns); + } + } + } + +} diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/pom.xml --- a/emul/mini/pom.xml Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/mini/pom.xml Tue Feb 05 08:27:42 2013 +0100 @@ -22,6 +22,12 @@ 0.3-SNAPSHOT jar + + org.testng + testng + 6.5.2 + test + diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/src/main/java/java/lang/Class.java --- a/emul/mini/src/main/java/java/lang/Class.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/mini/src/main/java/java/lang/Class.java Tue Feb 05 08:27:42 2013 +0100 @@ -231,12 +231,14 @@ } @JavaScriptBody(args = {"n", "c" }, body = - "if (vm[c]) return vm[c].$class;\n" - + "if (vm.loadClass) {\n" - + " vm.loadClass(n);\n" - + " if (vm[c]) return vm[c].$class;\n" + "if (!vm[c]) {\n" + + " if (vm.loadClass) {\n" + + " vm.loadClass(n);\n" + + " }\n" + + " if (!vm[c]) return null;\n" + "}\n" - + "return null;" + + "vm[c](false);" + + "return vm[c].$class;" ) private static native Class loadCls(String n, String c); diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/src/main/java/java/lang/Math.java --- a/emul/mini/src/main/java/java/lang/Math.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/mini/src/main/java/java/lang/Math.java Tue Feb 05 08:27:42 2013 +0100 @@ -991,9 +991,11 @@ * @author Joseph D. Darcy * @since 1.5 */ -// public static double signum(double d) { -// return sun.misc.FpUtils.signum(d); -// } + public static double signum(double d) { + if (d < 0.0) { return -1.0; } + if (d > 0.0) { return 1.0; } + return d; + } /** * Returns the signum function of the argument; zero if the argument @@ -1012,9 +1014,11 @@ * @author Joseph D. Darcy * @since 1.5 */ -// public static float signum(float f) { -// return sun.misc.FpUtils.signum(f); -// } + public static float signum(float f) { + if (f < 0.0f) { return -1.0f; } + if (f > 0.0f) { return 1.0f; } + return f; + } /** * Returns the first floating-point argument with the sign of the diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Tue Feb 05 08:27:42 2013 +0100 @@ -45,10 +45,13 @@ ) public static native byte[] expandArray(byte[] arr, int expectedSize); - @JavaScriptBody(args = {}, body = "new Date().getMilliseconds() * 1000;") - public static native long nanoTime(); + @JavaScriptBody(args = {}, body = "new Date().getMilliseconds();") + public static native long currentTimeMillis(); @JavaScriptBody(args = { "obj" }, body="return vm.java_lang_Object(false).hashCode__I.call(obj);") public static native int identityHashCode(Object obj); + public static long nanoTime() { + return 1000L * currentTimeMillis(); + } } diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/AnnotationImpl.java --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/AnnotationImpl.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/AnnotationImpl.java Tue Feb 05 08:27:42 2013 +0100 @@ -18,6 +18,8 @@ package org.apidesign.bck2brwsr.emul.reflect; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** @@ -25,39 +27,73 @@ * @author Jaroslav Tulach */ public final class AnnotationImpl implements Annotation { + private final Class type; + + public AnnotationImpl(Class type) { + this.type = type; + } + public Class annotationType() { - return getClass(); + return type; } - @JavaScriptBody(args = { "a", "n", "values" }, body = "" - + "function f(v, p) {\n" - + " var val = v;\n" - + " var prop = p;\n" + @JavaScriptBody(args = { "a", "n", "arr", "values" }, body = "" + + "function f(val, prop, clazz) {\n" + " return function() {\n" - + " return val[prop];\n" + + " if (clazz == null) return val[prop];\n" + + " if (clazz.isArray__Z()) {\n" + + " var valarr = val[prop];\n" + + " var cmp = clazz.getComponentType__Ljava_lang_Class_2();\n" + + " var retarr = vm.java_lang_reflect_Array(false).newInstance__Ljava_lang_Object_2Ljava_lang_Class_2I(cmp, valarr.length);\n" + + " for (var i = 0; i < valarr.length; i++) {\n" + + " retarr[i] = CLS.prototype.c__Ljava_lang_Object_2Ljava_lang_Class_2Ljava_lang_Object_2(cmp, valarr[i]);\n" + + " }\n" + + " return retarr;\n" + + " }\n" + + " return CLS.prototype.c__Ljava_lang_Object_2Ljava_lang_Class_2Ljava_lang_Object_2(clazz, val[prop]);\n" + " };\n" + "}\n" - + "var props = Object.getOwnPropertyNames(values);\n" - + "for (var i = 0; i < props.length; i++) {\n" - + " var p = props[i];\n" - + " a[p] = new f(values, p);\n" + + "for (var i = 0; i < arr.length; i += 3) {\n" + + " var m = arr[i];\n" + + " var p = arr[i + 1];\n" + + " var c = arr[i + 2];\n" + + " a[m] = f(values, p, c);\n" + "}\n" + "a['$instOf_' + n] = true;\n" + "return a;" ) - private static T create(AnnotationImpl a, String n, Object values) { - return null; + private static native T create( + AnnotationImpl a, String n, Object[] methodsAndProps, Object values + ); + + private static Object c(Class a, Object v) { + return create(a, v); } + public static T create(Class annoClass, Object values) { - return create(new AnnotationImpl(), annoClass.getName().replace('.', '_'), values); + return create(new AnnotationImpl(annoClass), + annoClass.getName().replace('.', '_'), + findProps(annoClass), values + ); } public static Annotation[] create(Object anno) { String[] names = findNames(anno); Annotation[] ret = new Annotation[names.length]; for (int i = 0; i < names.length; i++) { - String n = names[i].substring(1, names[i].length() - 1).replace('/', '_'); - ret[i] = create(new AnnotationImpl(), n, findData(anno, names[i])); + String annoNameSlash = names[i].substring(1, names[i].length() - 1); + Class annoClass; + try { + annoClass = (Class)Class.forName(annoNameSlash.replace('/', '.')); + } catch (ClassNotFoundException ex) { + throw new IllegalStateException("Can't find annotation class " + annoNameSlash); + } + ret[i] = create( + new AnnotationImpl(annoClass), + annoNameSlash.replace('/', '_'), + findProps(annoClass), + findData(anno, names[i]) + ); } return ret; } @@ -70,12 +106,25 @@ + "}" + "return arr;" ) - private static String[] findNames(Object anno) { - throw new UnsupportedOperationException(); - } + private static native String[] findNames(Object anno); @JavaScriptBody(args={ "anno", "p"}, body="return anno[p];") - private static Object findData(Object anno, String p) { - throw new UnsupportedOperationException(); + private static native Object findData(Object anno, String p); + + private static Object[] findProps(Class annoClass) { + final Method[] marr = MethodImpl.findMethods(annoClass, Modifier.PUBLIC); + Object[] arr = new Object[marr.length * 3]; + int pos = 0; + for (Method m : marr) { + arr[pos++] = MethodImpl.toSignature(m); + arr[pos++] = m.getName(); + final Class rt = m.getReturnType(); + if (rt.isArray()) { + arr[pos++] = rt.getComponentType().isAnnotation() ? rt : null; + } else { + arr[pos++] = rt.isAnnotation() ? rt : null; + } + } + return arr; } } diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Sat Feb 02 06:01:44 2013 +0100 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Tue Feb 05 08:27:42 2013 +0100 @@ -17,6 +17,7 @@ */ package org.apidesign.bck2brwsr.emul.reflect; +import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.Enumeration; import org.apidesign.bck2brwsr.core.JavaScriptBody; @@ -34,7 +35,7 @@ throw new IllegalStateException(ex); } } - + protected abstract Method create(Class declaringClass, String name, Object data, String sig); @@ -48,8 +49,10 @@ + "var arr = new Array();\n" + "for (m in c) {\n" + " if (m.indexOf(prefix) === 0) {\n" + + " if (!c[m].cls) continue;\n" + " arr.push(m);\n" + " arr.push(c[m]);\n" + + " arr.push(c[m].cls.$class);\n" + " }" + "}\n" + "return arr;") @@ -59,9 +62,10 @@ public static Method findMethod( Class clazz, String name, Class... parameterTypes) { Object[] data = findMethodData(clazz, name + "__"); - BIG: for (int i = 0; i < data.length; i += 2) { - String sig = ((String) data[0]).substring(name.length() + 2); - Method tmp = INSTANCE.create(clazz, name, data[1], sig); + BIG: for (int i = 0; i < data.length; i += 3) { + String sig = ((String) data[i]).substring(name.length() + 2); + Class cls = (Class) data[i + 2]; + Method tmp = INSTANCE.create(cls, name, data[i + 1], sig); Class[] tmpParms = tmp.getParameterTypes(); if (parameterTypes.length != tmpParms.length) { continue; @@ -79,7 +83,7 @@ public static Method[] findMethods(Class clazz, int mask) { Object[] namesAndData = findMethodData(clazz, ""); int cnt = 0; - for (int i = 0; i < namesAndData.length; i += 2) { + for (int i = 0; i < namesAndData.length; i += 3) { String sig = (String) namesAndData[i]; Object data = namesAndData[i + 1]; int middle = sig.indexOf("__"); @@ -88,7 +92,8 @@ } String name = sig.substring(0, middle); sig = sig.substring(middle + 2); - final Method m = INSTANCE.create(clazz, name, data, sig); + Class cls = (Class) namesAndData[i + 2]; + final Method m = INSTANCE.create(cls, name, data, sig); if ((m.getModifiers() & mask) == 0) { continue; } @@ -100,6 +105,62 @@ } return arr; } + static String toSignature(Method m) { + StringBuilder sb = new StringBuilder(); + sb.append(m.getName()).append("__"); + appendType(sb, m.getReturnType()); + Class[] arr = m.getParameterTypes(); + for (int i = 0; i < arr.length; i++) { + appendType(sb, arr[i]); + } + return sb.toString(); + } + + private static void appendType(StringBuilder sb, Class type) { + if (type == Integer.TYPE) { + sb.append('I'); + return; + } + if (type == Long.TYPE) { + sb.append('J'); + return; + } + if (type == Double.TYPE) { + sb.append('D'); + return; + } + if (type == Float.TYPE) { + sb.append('F'); + return; + } + if (type == Byte.TYPE) { + sb.append('B'); + return; + } + if (type == Boolean.TYPE) { + sb.append('Z'); + return; + } + if (type == Short.TYPE) { + sb.append('S'); + return; + } + if (type == Void.TYPE) { + sb.append('V'); + return; + } + if (type == Character.TYPE) { + sb.append('C'); + return; + } + if (type.isArray()) { + sb.append("_3"); + appendType(sb, type.getComponentType()); + return; + } + sb.append('L').append(type.getName().replace('.', '_')); + sb.append("_2"); + } public static int signatureElements(String sig) { Enumeration en = signatureParser(sig); @@ -141,13 +202,19 @@ return Character.TYPE; case 'L': try { - int up = sig.indexOf("_2"); - String type = sig.substring(1, up); + int up = sig.indexOf("_2", pos); + String type = sig.substring(pos, up); pos = up + 2; - return Class.forName(type); + return Class.forName(type.replace('_', '.')); } catch (ClassNotFoundException ex) { - // should not happen + throw new IllegalStateException(ex); } + case '_': { + char nch = sig.charAt(pos++); + assert nch == '3' : "Can't find '3' at " + sig.substring(pos - 1); + final Class compType = nextElement(); + return Array.newInstance(compType, 0).getClass(); + } } throw new UnsupportedOperationException(sig + " at " + pos); } diff -r 6b77554987e0 -r 8338ab1991e6 emul/mini/src/test/java/org/apidesign/bck2brwsr/emul/reflect/MethodImplTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/test/java/org/apidesign/bck2brwsr/emul/reflect/MethodImplTest.java Tue Feb 05 08:27:42 2013 +0100 @@ -0,0 +1,49 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.emul.reflect; + +import java.lang.reflect.Method; +import java.util.Enumeration; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class MethodImplTest { + + public MethodImplTest() { + } + + public static String[] arr(String... arr) { + return arr; + } + + @Test + public void testSignatureForMethodWithAnArray() throws NoSuchMethodException { + Method m = MethodImplTest.class.getMethod("arr", String[].class); + String sig = MethodImpl.toSignature(m); + int sep = sig.indexOf("__"); + assert sep > 0 : "Separator found " + sig; + + Enumeration en = MethodImpl.signatureParser(sig.substring(sep + 2)); + + assert en.nextElement() == m.getReturnType() : "Return type is the same"; + assert en.nextElement() == m.getParameterTypes()[0] : "1st param type is the same"; + } +} \ No newline at end of file diff -r 6b77554987e0 -r 8338ab1991e6 javap/src/main/java/org/apidesign/javap/AnnotationParser.java --- a/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Sat Feb 02 06:01:44 2013 +0100 +++ b/javap/src/main/java/org/apidesign/javap/AnnotationParser.java Tue Feb 05 08:27:42 2013 +0100 @@ -35,22 +35,37 @@ */ public class AnnotationParser { private final boolean textual; + private final boolean iterateArray; - protected AnnotationParser(boolean textual) { + protected AnnotationParser(boolean textual, boolean iterateArray) { this.textual = textual; + this.iterateArray = iterateArray; } - protected void visitAnnotationStart(String type) throws IOException { + protected void visitAnnotationStart(String type, boolean top) throws IOException { } - protected void visitAnnotationEnd(String type) throws IOException { + protected void visitAnnotationEnd(String type, boolean top) throws IOException { } + + protected void visitValueStart(String attrName, char type) throws IOException { + } + + protected void visitValueEnd(String attrName, char type) throws IOException { + } + protected void visitAttr( String annoType, String attr, String attrType, String value ) throws IOException { } + protected void visitEnumAttr( + String annoType, String attr, String attrType, String value + ) throws IOException { + visitAttr(annoType, attr, attrType, value); + } + /** Initialize the parsing with constant pool from cd. * * @param attr the attribute defining annotations @@ -70,30 +85,32 @@ private void read(DataInputStream dis, ClassData cd) throws IOException { int cnt = dis.readUnsignedShort(); for (int i = 0; i < cnt; i++) { - readAnno(dis, cd); + readAnno(dis, cd, true); } } - private void readAnno(DataInputStream dis, ClassData cd) throws IOException { + private void readAnno(DataInputStream dis, ClassData cd, boolean top) throws IOException { int type = dis.readUnsignedShort(); String typeName = cd.StringValue(type); - visitAnnotationStart(typeName); + visitAnnotationStart(typeName, top); int cnt = dis.readUnsignedShort(); for (int i = 0; i < cnt; i++) { String attrName = cd.StringValue(dis.readUnsignedShort()); readValue(dis, cd, typeName, attrName); } - visitAnnotationEnd(typeName); + visitAnnotationEnd(typeName, top); if (cnt == 0) { visitAttr(typeName, null, null, null); } } - private void readValue(DataInputStream dis, ClassData cd, String typeName, String attrName) - throws IOException { + private void readValue( + DataInputStream dis, ClassData cd, String typeName, String attrName + ) throws IOException { char type = (char)dis.readByte(); + visitValueStart(attrName, type); if (type == '@') { - readAnno(dis, cd); + readAnno(dis, cd, false); } else if ("CFJZsSIDB".indexOf(type) >= 0) { // NOI18N int primitive = dis.readUnsignedShort(); String val = cd.stringValue(primitive, textual); @@ -112,13 +129,17 @@ } else if (type == '[') { int cnt = dis.readUnsignedShort(); for (int i = 0; i < cnt; i++) { - readValue(dis, cd, typeName, attrName); + readValue(dis, cd, typeName, iterateArray ? attrName : null); } } else if (type == 'e') { int enumT = dis.readUnsignedShort(); + String attrType = cd.stringValue(enumT, textual); int enumN = dis.readUnsignedShort(); + String val = cd.stringValue(enumN, textual); + visitEnumAttr(typeName, attrName, attrType, val); } else { throw new IOException("Unknown type " + type); } + visitValueEnd(attrName, type); } } diff -r 6b77554987e0 -r 8338ab1991e6 mojo/src/main/resources/archetype-resources/pom.xml --- a/mojo/src/main/resources/archetype-resources/pom.xml Sat Feb 02 06:01:44 2013 +0100 +++ b/mojo/src/main/resources/archetype-resources/pom.xml Tue Feb 05 08:27:42 2013 +0100 @@ -60,7 +60,7 @@ test - ${project.groupId} + org.apidesign.bck2brwsr vmtest 0.3-SNAPSHOT test diff -r 6b77554987e0 -r 8338ab1991e6 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sat Feb 02 06:01:44 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Feb 05 08:27:42 2013 +0100 @@ -175,6 +175,7 @@ out.append("\n };"); } out.append(prefix).append(mn).append(".access = " + m.getAccess()).append(";"); + out.append(prefix).append(mn).append(".cls = CLS;"); } out.append("\n c.constructor = CLS;"); out.append("\n c.$instOf_").append(className).append(" = true;"); @@ -1605,7 +1606,7 @@ final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;"; class P extends AnnotationParser { public P() { - super(false); + super(false, true); } int cnt; @@ -1661,7 +1662,7 @@ final String[] values = new String[attrNames.length]; final boolean[] found = { false }; final String jvmType = "L" + className.replace('.', '/') + ";"; - AnnotationParser ap = new AnnotationParser(false) { + AnnotationParser ap = new AnnotationParser(false, true) { @Override protected void visitAttr(String type, String attr, String at, String value) { if (type.equals(jvmType)) { @@ -1698,35 +1699,71 @@ return " = null;"; } - private static void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException { - AnnotationParser ap = new AnnotationParser(true) { - int anno; - int cnt; + private void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException { + AnnotationParser ap = new AnnotationParser(true, false) { + int[] cnt = new int[32]; + int depth; @Override - protected void visitAnnotationStart(String type) throws IOException { - if (anno++ > 0) { + protected void visitAnnotationStart(String attrType, boolean top) throws IOException { + final String slashType = attrType.substring(1, attrType.length() - 1); + requireReference(slashType); + + if (cnt[depth]++ > 0) { out.append(","); } - out.append('"').append(type).append("\" : {\n"); - cnt = 0; + if (top) { + out.append('"').append(attrType).append("\" : "); + } + out.append("{\n"); + cnt[++depth] = 0; } @Override - protected void visitAnnotationEnd(String type) throws IOException { + protected void visitAnnotationEnd(String type, boolean top) throws IOException { out.append("\n}\n"); + depth--; + } + + @Override + protected void visitValueStart(String attrName, char type) throws IOException { + if (cnt[depth]++ > 0) { + out.append(",\n"); + } + cnt[++depth] = 0; + if (attrName != null) { + out.append(attrName).append(" : "); + } + if (type == '[') { + out.append("["); + } + } + + @Override + protected void visitValueEnd(String attrName, char type) throws IOException { + if (type == '[') { + out.append("]"); + } + depth--; } @Override protected void visitAttr(String type, String attr, String attrType, String value) throws IOException { - if (attr == null) { + if (attr == null && value == null) { return; } - if (cnt++ > 0) { - out.append(",\n"); - } - out.append(attr).append("__").append(attrType).append(" : ").append(value); + out.append(value); + } + + @Override + protected void visitEnumAttr(String type, String attr, String attrType, String value) + throws IOException { + final String slashType = attrType.substring(1, attrType.length() - 1); + requireReference(slashType); + + out.append(accessClass(slashType.replace('/', '_'))) + .append("(false).constructor.").append(value); } }; ap.parse(data, cd); diff -r 6b77554987e0 -r 8338ab1991e6 vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Sat Feb 02 06:01:44 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Tue Feb 05 08:27:42 2013 +0100 @@ -87,12 +87,27 @@ @Test public void jsAnnotation() throws Exception { assertExec("Check class annotation", Classes.class, "getMarker__I", Double.valueOf(10)); } + @Test public void jsArrayAnnotation() throws Exception { + assertExec("Check array annotation", Classes.class, "getMarkerNicknames__Ljava_lang_String_2", Classes.getMarkerNicknames()); + } + @Test public void jsEnumAnnotation() throws Exception { + assertExec("Check enum annotation", Classes.class, "getMarkerE__Ljava_lang_String_2", Classes.getMarkerE()); + } + @Test public void jsRetentionAnnotation() throws Exception { + assertExec("Check enum annotation", Classes.class, "getRetention__Ljava_lang_String_2", Classes.getRetention()); + } @Test public void jsStringAnnotation() throws Exception { assertExec("Check class annotation", Classes.class, "getNamer__Ljava_lang_String_2Z", "my text", true); } @Test public void jsStringAnnotationFromArray() throws Exception { assertExec("Check class annotation", Classes.class, "getNamer__Ljava_lang_String_2Z", "my text", false); } + @Test public void jsInnerAnnotation() throws Exception { + assertExec("Check inner annotation", Classes.class, "getInnerNamer__I", Double.valueOf(Classes.getInnerNamer())); + } + @Test public void jsInnerAnnotationFromArray() throws Exception { + assertExec("Check inner annotation", Classes.class, "getInnerNamers__I", Double.valueOf(Classes.getInnerNamers())); + } @Test public void javaInvokeMethod() throws Exception { assertEquals(Classes.reflectiveMethodCall(true, "name"), "java.io.IOException", "Calls the name() method via reflection"); } @@ -102,6 +117,14 @@ "java.io.IOException", true, "name" ); } + + @Test public void jsMethodDeclaredInObject() throws Exception { + assertExec("Defined in Object", Classes.class, + "objectName__Ljava_lang_String_2", + "java.lang.Object" + ); + } + @Test public void jsInvokeParamMethod() throws Exception { assertExec("sums two numbers via reflection", Classes.class, "reflectiveSum__III", Double.valueOf(5), 2, 3 @@ -149,14 +172,12 @@ 0.0, "java.lang.String" ); } - /* @Test public void isInterface() throws Exception { assertExec("Calls Class.isInterface", Classes.class, "isInterface__ZLjava_lang_String_2", 1.0, "java.lang.Runnable" ); } - */ @Test public void integerType() throws Exception { assertExec("Computes the type", Classes.class, "intType__Ljava_lang_String_2", diff -r 6b77554987e0 -r 8338ab1991e6 vm/src/test/java/org/apidesign/vm4brwsr/Classes.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Sat Feb 02 06:01:44 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Tue Feb 05 08:27:42 2013 +0100 @@ -19,6 +19,8 @@ import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.net.MalformedURLException; import org.apidesign.bck2brwsr.core.JavaScriptBody; @@ -27,8 +29,11 @@ * * @author Jaroslav Tulach */ -@ClassesMarker(number = 10) -@ClassesNamer(name = "my text") +@ClassesMarker(number = 10, nicknames = { "Ten", "Deset" }, count = ClassesMarker.E.TWO, subs = { + @ClassesMarker.Anno(Integer.SIZE), + @ClassesMarker.Anno(Integer.MIN_VALUE) +}) +@ClassesNamer(name = "my text", anno = @ClassesMarker.Anno(333)) public class Classes { public static String nameOfIO() { return nameFor(IOException.class); @@ -38,6 +43,8 @@ return c.getName(); } + private static final Class PRELOAD = Runnable.class; + public static boolean isInterface(String s) throws ClassNotFoundException { return Class.forName(s).isInterface(); } @@ -55,7 +62,7 @@ return new IOException().getClass().getName().toString(); } - @ClassesMarker(number = 1) + @ClassesMarker(number = 1, nicknames = { "One", "Jedna" } ) public static String name() { return IOException.class.getName().toString(); } @@ -65,6 +72,11 @@ public static String canonicalName() { return IOException.class.getCanonicalName(); } + + public static String objectName() throws NoSuchMethodException { + return IOException.class.getMethod("wait").getDeclaringClass().getName(); + } + public static boolean newInstance() throws Exception { IOException ioe = IOException.class.newInstance(); if (ioe instanceof IOException) { @@ -85,8 +97,45 @@ return -2; } ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class); + assert cm instanceof Object : "Is object " + cm; + assert cm instanceof Annotation : "Is annotation " + cm; + assert !((Object)cm instanceof Class) : "Is not Class " + cm; return cm == null ? -1 : cm.number(); } + public static String getMarkerNicknames() { + ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class); + if (cm == null) { + return null; + } + + final Object[] arr = cm.nicknames(); + assert arr instanceof Object[] : "Instance of Object array: " + arr; + assert arr instanceof String[] : "Instance of String array: " + arr; + assert !(arr instanceof Integer[]) : "Not instance of Integer array: " + arr; + + StringBuilder sb = new StringBuilder(); + for (String s : cm.nicknames()) { + sb.append(s).append("\n"); + } + return sb.toString().toString(); + } + @Retention(RetentionPolicy.CLASS) + @interface Ann { + } + + public static String getRetention() throws Exception { + Retention r = Ann.class.getAnnotation(Retention.class); + assert r != null : "Annotation is present"; + assert r.value() == RetentionPolicy.CLASS : "Policy value is OK: " + r.value(); + return r.annotationType().getName(); + } + public static String getMarkerE() { + ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class); + if (cm == null) { + return null; + } + return cm.count().name(); + } public static String getNamer(boolean direct) { if (direct) { ClassesNamer cm = Classes.class.getAnnotation(ClassesNamer.class); @@ -99,6 +148,20 @@ } return null; } + public static int getInnerNamer() { + ClassesNamer cm = Classes.class.getAnnotation(ClassesNamer.class); + assert cm != null : "ClassesNamer is present"; + return cm.anno().value(); + } + public static int getInnerNamers() { + ClassesMarker cm = Classes.class.getAnnotation(ClassesMarker.class); + assert cm != null : "ClassesNamer is present"; + int sum = 0; + for (ClassesMarker.Anno anno : cm.subs()) { + sum += anno.value(); + } + return sum; + } public static String intType() { return Integer.TYPE.getName(); diff -r 6b77554987e0 -r 8338ab1991e6 vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java Sat Feb 02 06:01:44 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassesMarker.java Tue Feb 05 08:27:42 2013 +0100 @@ -27,4 +27,16 @@ @Retention(RetentionPolicy.RUNTIME) public @interface ClassesMarker { int number(); + String[] nicknames(); + E count() default E.ONE; + + enum E { + ONE, TWO; + } + + Anno[] subs() default {}; + + public @interface Anno { + int value(); + } } diff -r 6b77554987e0 -r 8338ab1991e6 vm/src/test/java/org/apidesign/vm4brwsr/ClassesNamer.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassesNamer.java Sat Feb 02 06:01:44 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassesNamer.java Tue Feb 05 08:27:42 2013 +0100 @@ -27,4 +27,5 @@ @Retention(RetentionPolicy.RUNTIME) public @interface ClassesNamer { String name(); + ClassesMarker.Anno anno(); } diff -r 6b77554987e0 -r 8338ab1991e6 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Sat Feb 02 06:01:44 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Tue Feb 05 08:27:42 2013 +0100 @@ -17,6 +17,8 @@ */ package org.apidesign.bck2brwsr.tck; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; @@ -47,6 +49,14 @@ return long.class.toString(); } + @Compare public boolean isRunnableInterface() { + return Runnable.class.isInterface(); + } + + @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException { + return Runnable.class.getMethod("run").getName(); + } + @Compare public String namesOfMethods() { StringBuilder sb = new StringBuilder(); String[] arr = new String[20]; @@ -59,6 +69,19 @@ } return sb.toString(); } + + @Compare public String namesOfDeclaringClassesOfMethods() { + StringBuilder sb = new StringBuilder(); + String[] arr = new String[20]; + int i = 0; + for (Method m : StaticUse.class.getMethods()) { + arr[i++] = m.getName() + "@" + m.getDeclaringClass().getName(); + } + for (String s : sort(arr, i)) { + sb.append(s).append("\n"); + } + return sb.toString(); + } @Compare public String cannotCallNonStaticMethodWithNull() throws Exception { StaticUse.class.getMethod("instanceMethod").invoke(null); @@ -69,6 +92,26 @@ return StaticUse.class.getMethod("instanceMethod").getReturnType(); } + @Retention(RetentionPolicy.RUNTIME) + @interface Ann { + } + + @Compare public String annoClass() throws Exception { + Retention r = Ann.class.getAnnotation(Retention.class); + assert r != null : "Annotation is present"; + assert r.value() == RetentionPolicy.RUNTIME : "Policy value is OK: " + r.value(); + return r.annotationType().getName(); + } + + @Compare public boolean isAnnotation() { + return Ann.class.isAnnotation(); + } + @Compare public boolean isNotAnnotation() { + return String.class.isAnnotation(); + } + @Compare public boolean isNotAnnotationEnum() { + return E.class.isAnnotation(); + } enum E { A, B }; @Compare public boolean isEnum() { return E.A.getClass().isEnum();