package com.redhat.ceylon.compiler.java;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.util.Arrays;
import ceylon.language.ArraySequence;
import ceylon.language.AssertionError;
import ceylon.language.Callable;
import ceylon.language.Finished;
import ceylon.language.Integer;
import ceylon.language.Iterable;
import ceylon.language.Iterator;
import ceylon.language.Null;
import ceylon.language.OverflowException;
import ceylon.language.Ranged;
import ceylon.language.Sequence;
import ceylon.language.Sequential;
import ceylon.language.Tuple;
import ceylon.language.empty_;
import ceylon.language.finished_;
import ceylon.language.sequence_;
import com.redhat.ceylon.cmr.api.ArtifactResult;
import com.redhat.ceylon.compiler.java.language.AbstractArrayIterable;
import com.redhat.ceylon.compiler.java.language.ObjectArray.ObjectArrayIterable;
import com.redhat.ceylon.compiler.java.metadata.Class;
import com.redhat.ceylon.compiler.java.metadata.Name;
import com.redhat.ceylon.compiler.java.metadata.TypeInfo;
import com.redhat.ceylon.compiler.java.runtime.metamodel.Metamodel;
import com.redhat.ceylon.compiler.java.runtime.model.TypeDescriptor;
/**
* Helper class for generated Ceylon code that needs to call implementation logic.
*
* @author Stéphane Épardaud <stef@epardaud.fr>
*/
public class Util {
static {
// Make sure the rethrow class is loaded if ever we need to rethrow
// errors such as StackOverflowError, otherwise if we have to rethrow it
// we will not be able to load that class since we've ran out of stack
// see https://github.com/ceylon/ceylon.language/issues/311
ceylon.language.impl.rethrow_.class.toString();
}
private static final int INIT_ARRAY_SIZE = 10;
public static String declClassName(String name) {
return name.replace("::", ".");
}
public static void loadModule(String name, String version,
ArtifactResult result, ClassLoader classLoader) {
Metamodel.loadModule(name, version, result, classLoader);
}
public static boolean isReified(java.lang.Object o, TypeDescriptor type) {
return Metamodel.isReified(o, type);
}
/**
* Returns true if the given object satisfies ceylon.language.Identifiable
*/
public static boolean isIdentifiable(java.lang.Object o) {
if(o == null)
return false;
Class classAnnotation = getClassAnnotationForIdentifiableOrBasic(o);
// unless marked as NOT identifiable, every instance is Identifiable
return classAnnotation != null ? classAnnotation.identifiable() : true;
}
private static Class getClassAnnotationForIdentifiableOrBasic(Object o) {
java.lang.Class<? extends Object> klass = o.getClass();
while(klass != null && klass != java.lang.Object.class) {
Class classAnnotation = klass.getAnnotation(Class.class);
if(classAnnotation != null) {
return classAnnotation;
}
// else keep looking up
klass = klass.getSuperclass();
}
// no annotation found
return null;
}
/**
* Returns true if the given object extends ceylon.language.Basic
*/
public static boolean isBasic(java.lang.Object o) {
if (o == null)
return false;
Class classAnnotation = getClassAnnotationForIdentifiableOrBasic(o);
// unless marked as NOT identifiable, every instance is Basic
return classAnnotation != null ? classAnnotation.basic() : true;
}
//
// Java variadic conversions
/** Return the size of the given iterable if we know it can be computed
* efficiently (typically without iterating the iterable)
*/
private static <T> int fastIterableSize(Iterable<? extends T, ?> iterable) {
if (iterable instanceof Sequential
|| iterable instanceof AbstractArrayIterable) {
return toInt(iterable.getSize());
}
return -1;
}
@SuppressWarnings("unchecked")
private static <T> void fillArray(T[] array, int offset,
Iterable<? extends T, ?> iterable) {
Iterator<?> iterator = iterable.iterator();
Object o;
int index = offset;
while ((o = iterator.next()) != finished_.get_()) {
array[index] = (T) o;
index++;
}
}
/**
* Base class for a family of builders for Java native arrays.
*
* Encapsulation has been sacraficed for efficiency.
*
* @param <A> an array type such as int[]
*/
public static abstract class ArrayBuilder<A> {
private static final int MIN_CAPACITY = 5;
private static final int MAX_CAPACITY = java.lang.Integer.MAX_VALUE;
/** The number of elements in {@link #array}. This is always <= {@link #capacity} */
protected int size;
/** The length of {@link #array} */
protected int capacity;
/** The array */
protected A array;
ArrayBuilder(int initialSize) {
capacity = Math.max(initialSize, MIN_CAPACITY);
array = allocate(capacity);
size = 0;
}
/** Append all the elements in the given array */
final void appendArray(A elements) {
int increment = size(elements);
int newsize = this.size + increment;
ensure(newsize);
System.arraycopy(elements, 0, array, this.size, increment);
this.size = newsize;
}
/** Ensure the {@link #array} is as big, or bigger than the given capacity */
protected final void ensure(int requestedCapacity) {
if (this.capacity >= requestedCapacity) {
return;
}
int newcapacity = requestedCapacity+(requestedCapacity>>1);
if (newcapacity < MIN_CAPACITY) {
newcapacity = MIN_CAPACITY;
} else if (newcapacity > MAX_CAPACITY) {
newcapacity = requestedCapacity;
if (newcapacity > MAX_CAPACITY) {
throw new AssertionError("can't allocate array bigger than " + MAX_CAPACITY);
}
}
A newArray = allocate(newcapacity);
System.arraycopy(this.array, 0, newArray, 0, this.size);
this.capacity = newcapacity;
this.array = newArray;
}
/**
* Allocate and return an array of the given size
*/
protected abstract A allocate(int size);
/**
* The size of the given array
*/
protected abstract int size(A array);
/**
* Returns an array of exactly the right size to contain all the
* appended elements.
*/
A build() {
if (this.capacity == this.size) {
return array;
}
A result = allocate(this.size);
System.arraycopy(this.array, 0, result, 0, this.size);
return result;
}
}
/**
* An array builder whose result is an {@code Object[]}.
* @see ReflectingObjectArrayBuilder
*/
static final class ObjectArrayBuilder
extends ArrayBuilder<Object[]> {
ObjectArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected Object[] allocate(int size) {
return new Object[size];
}
@Override
protected int size(Object[] array) {
return array.length;
}
void appendRef(Object t) {
ensure(size+1);
array[size] = t;
size++;
}
}
/**
* An array builder whose result is an array of a given component type, that is, {@code T[]}.
* The intermediate arrays are {@code Object[]}.
* @see ObjectArrayBuilder
*/
public static final class ReflectingObjectArrayBuilder<T>
extends ArrayBuilder<T[]> {
private final java.lang.Class<T> klass;
public ReflectingObjectArrayBuilder(int initialSize,
java.lang.Class<T> klass) {
super(initialSize);
this.klass = klass;
}
@SuppressWarnings("unchecked")
@Override
protected T[] allocate(int size) {
return (T[])new Object[size];
}
@Override
protected int size(T[] array) {
return array.length;
}
public void appendRef(T t) {
ensure(size+1);
array[size] = t;
size++;
}
public T[] build() {
@SuppressWarnings("unchecked")
T[] result = (T[])java.lang.reflect.Array.newInstance(klass, this.size);
System.arraycopy(this.array, 0, result, 0, this.size);
return result;
}
}
/**
* An array builder whose result is a {@code int[]}.
*/
static final class IntArrayBuilder
extends ArrayBuilder<int[]> {
IntArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected int[] allocate(int size) {
return new int[size];
}
@Override
protected int size(int[] array) {
return array.length;
}
void appendInt(int i) {
ensure(size+1);
array[size] = i;
size++;
}
void appendLong(long i) {
appendInt(toInt(i));
}
}
/**
* An array builder whose result is a {@code long[]}.
*/
static final class LongArrayBuilder
extends ArrayBuilder<long[]> {
LongArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected long[] allocate(int size) {
return new long[size];
}
@Override
protected int size(long[] array) {
return array.length;
}
void appendLong(long i) {
ensure(size+1);
array[size] = i;
size++;
}
}
/**
* An array builder whose result is a {@ocde boolean[]}.
*/
static final class BooleanArrayBuilder
extends ArrayBuilder<boolean[]> {
BooleanArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected boolean[] allocate(int size) {
return new boolean[size];
}
@Override
protected int size(boolean[] array) {
return array.length;
}
void appendBoolean(boolean b) {
ensure(size+1);
array[size] = b;
size++;
}
}
/**
* An array builder whose result is a {@code byte[]}.
*/
static final class ByteArrayBuilder
extends ArrayBuilder<byte[]> {
ByteArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected byte[] allocate(int size) {
return new byte[size];
}
@Override
protected int size(byte[] array) {
return array.length;
}
void appendByte(byte b) {
ensure(size+1);
array[size] = b;
size++;
}
}
/**
* An array builder whose result is a {@code short[]}.
*/
static final class ShortArrayBuilder
extends ArrayBuilder<short[]> {
ShortArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected short[] allocate(int size) {
return new short[size];
}
@Override
protected int size(short[] array) {
return array.length;
}
void appendShort(short b) {
ensure(size+1);
array[size] = b;
size++;
}
void appendLong(long b) {
appendShort(toShort(b));
}
}
/**
* An array builder whose result is a {@code double[]}.
*/
static final class DoubleArrayBuilder
extends ArrayBuilder<double[]> {
DoubleArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected double[] allocate(int size) {
return new double[size];
}
@Override
protected int size(double[] array) {
return array.length;
}
void appendDouble(double i) {
ensure(size+1);
array[size] = i;
size++;
}
}
/**
* An array builder whose result is a {@code float[]}.
*/
static final class FloatArrayBuilder
extends ArrayBuilder<float[]> {
FloatArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected float[] allocate(int size) {
return new float[size];
}
@Override
protected int size(float[] array) {
return array.length;
}
void appendFloat(float i) {
ensure(size+1);
array[size] = i;
size++;
}
void appendDouble(double d) {
appendFloat((float)d);
}
}
/**
* An array builder whose result is a {@code char[]}.
*/
static final class CharArrayBuilder
extends ArrayBuilder<char[]> {
CharArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected char[] allocate(int size) {
return new char[size];
}
@Override
protected int size(char[] array) {
return array.length;
}
void appendChar(char b) {
ensure(size+1);
array[size] = b;
size++;
}
void appendCodepoint(int codepoint) {
if (Character.charCount(codepoint) == 1) {
appendChar((char)codepoint);
} else {
appendChar(Character.highSurrogate(codepoint));
appendChar(Character.lowSurrogate(codepoint));
}
}
}
/**
* An array builder whose result is a {@code java.lang.String[]}.
*/
static final class StringArrayBuilder
extends ArrayBuilder<java.lang.String[]> {
StringArrayBuilder(int initialSize) {
super(initialSize);
}
@Override
protected java.lang.String[] allocate(int size) {
return new java.lang.String[size];
}
@Override
protected int size(java.lang.String[] array) {
return array.length;
}
void appendString(java.lang.String b) {
ensure(size+1);
array[size] = b;
size++;
}
void appendCeylonString(ceylon.language.String javaString) {
appendString(javaString.value);
}
}
@SuppressWarnings("unchecked")
public static boolean[]
toBooleanArray(ceylon.language.Iterable<? extends ceylon.language.Boolean, ?> sequence,
boolean... initialElements) {
if (sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Boolean> list =
(ceylon.language.List<? extends ceylon.language.Boolean>) sequence;
return toBooleanArray(list, initialElements);
}
BooleanArrayBuilder builder =
new BooleanArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
builder.appendArray(initialElements);
Iterator<? extends ceylon.language.Boolean> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendBoolean(((ceylon.language.Boolean) o).booleanValue());
}
return builder.build();
}
public static boolean[]
toBooleanArray(ceylon.language.List<? extends ceylon.language.Boolean> list,
boolean... initialElements) {
if (list == null)
return initialElements;
int i=initialElements.length;
boolean[] ret = new boolean[toInt(list.getSize() + i)];
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends ceylon.language.Boolean> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = ((ceylon.language.Boolean) o).booleanValue();
}
return ret;
}
@SuppressWarnings("unchecked")
public static byte[]
toByteArray(ceylon.language.Iterable<? extends ceylon.language.Byte, ?> sequence,
byte... initialElements) {
if (sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Byte> list =
(ceylon.language.List<? extends ceylon.language.Byte>) sequence;
return toByteArray(list, initialElements);
}
ByteArrayBuilder builder =
new ByteArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
int i=0;
for(;i<initialElements.length;i++) {
builder.appendByte(initialElements[i]);
}
Iterator<? extends ceylon.language.Byte> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendByte(((ceylon.language.Byte) o).byteValue());
}
return builder.build();
}
public static byte[]
toByteArray(ceylon.language.List<? extends ceylon.language.Byte> list,
byte... initialElements) {
byte[] ret = new byte[(list == null ? 0 : toInt(list.getSize()) + initialElements.length)];
int i=0;
for (;i<initialElements.length;i++) {
ret[i] = initialElements[i];
}
if (list != null) {
Iterator<? extends ceylon.language.Byte> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = ((ceylon.language.Byte) o).byteValue();
}
}
return ret;
}
@SuppressWarnings("unchecked")
public static short[]
toShortArray(ceylon.language.Iterable<? extends ceylon.language.Integer, ?> sequence,
long... initialElements) {
if(sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Integer> list =
(ceylon.language.List<? extends ceylon.language.Integer>) sequence;
return toShortArray(list, initialElements);
}
ShortArrayBuilder builder =
new ShortArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
int i=0;
for(;i<initialElements.length;i++) {
builder.appendLong(initialElements[i]);
}
Iterator<? extends ceylon.language.Integer> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendLong(((ceylon.language.Integer) o).longValue());
}
return builder.build();
}
public static short[]
toShortArray(ceylon.language.List<? extends ceylon.language.Integer> list,
long... initialElements) {
short[] ret = new short[(list == null ? 0 : toInt(list.getSize()) + initialElements.length)];
int i=0;
for (;i<initialElements.length;i++) {
ret[i] = toShort(initialElements[i]);
}
if (list != null) {
Iterator<? extends ceylon.language.Integer> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = toShort(((ceylon.language.Integer) o).longValue());
}
}
return ret;
}
@SuppressWarnings("unchecked")
public static int[]
toIntArray(ceylon.language.Iterable<? extends ceylon.language.Integer, ?> sequence,
long... initialElements) {
if(sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Integer> list =
(ceylon.language.List<? extends ceylon.language.Integer>) sequence;
return toIntArray(list,
initialElements);
}
IntArrayBuilder builder =
new IntArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
int i=0;
for(;i<initialElements.length;i++) {
builder.appendLong(initialElements[i]);
}
Iterator<? extends ceylon.language.Integer> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendLong(((ceylon.language.Integer) o).longValue());
}
return builder.build();
}
public static int[]
toIntArray(ceylon.language.List<? extends ceylon.language.Integer> list,
long... initialElements) {
int[] ret = new int[(list == null ? 0 : toInt(list.getSize()) + initialElements.length)];
int i=0;
for (;i<initialElements.length;i++) {
ret[i] = toInt(initialElements[i]);
}
if (list != null) {
Iterator<? extends ceylon.language.Integer> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = toInt(((ceylon.language.Integer) o).longValue());
}
}
return ret;
}
@SuppressWarnings("unchecked")
public static long[]
toLongArray(ceylon.language.Iterable<? extends ceylon.language.Integer, ?> sequence,
long... initialElements) {
if(sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Integer> list =
(ceylon.language.List<? extends ceylon.language.Integer>) sequence;
return toLongArray(list, initialElements);
}
LongArrayBuilder builder =
new LongArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
builder.appendArray(initialElements);
Iterator<? extends ceylon.language.Integer> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendLong(((ceylon.language.Integer) o).longValue());
}
return builder.build();
}
public static long[]
toLongArray(ceylon.language.List<? extends ceylon.language.Integer> list,
long... initialElements) {
if (list == null)
return initialElements;
int i=initialElements.length;
long[] ret = new long[toInt(list.getSize() + i)];
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends ceylon.language.Integer> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = ((ceylon.language.Integer) o).longValue();
}
return ret;
}
@SuppressWarnings("unchecked")
public static float[]
toFloatArray(ceylon.language.Iterable<? extends ceylon.language.Float, ?> sequence,
double... initialElements) {
if(sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Float> list =
(ceylon.language.List<? extends ceylon.language.Float>) sequence;
return toFloatArray(list, initialElements);
}
FloatArrayBuilder builder =
new FloatArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
int i=0;
for (;i<initialElements.length;i++) {
builder.appendDouble(initialElements[i]);
}
Iterator<? extends ceylon.language.Float> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendDouble(((ceylon.language.Float)o).doubleValue());
}
return builder.build();
}
public static float[]
toFloatArray(ceylon.language.List<? extends ceylon.language.Float> list,
double... initialElements) {
float[] ret = new float[(list == null ? 0 : toInt(list.getSize()) + initialElements.length)];
int i=0;
for (;i<initialElements.length;i++) {
ret[i] = (float) initialElements[i];
}
if (list != null) {
Iterator<? extends ceylon.language.Float> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = (float)((ceylon.language.Float) o).doubleValue();
}
}
return ret;
}
@SuppressWarnings("unchecked")
public static double[]
toDoubleArray(ceylon.language.Iterable<? extends ceylon.language.Float, ?> sequence,
double... initialElements) {
if (sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Float> list =
(ceylon.language.List<? extends ceylon.language.Float>) sequence;
return toDoubleArray(list, initialElements);
}
DoubleArrayBuilder builder =
new DoubleArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
builder.appendArray(initialElements);
Iterator<? extends ceylon.language.Float> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendDouble(((ceylon.language.Float) o).doubleValue());
}
return builder.build();
}
public static double[]
toDoubleArray(ceylon.language.List<? extends ceylon.language.Float> list,
double... initialElements) {
if (list == null)
return initialElements;
int i=initialElements.length;
double[] ret = new double[toInt(list.getSize() + i)];
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends ceylon.language.Float> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = ((ceylon.language.Float) o).doubleValue();
}
return ret;
}
public static char[]
toCharArray(ceylon.language.Iterable<? extends ceylon.language.Character, ?> sequence,
int... initialElements) {
// Note the List optimization doesn't work because
// the number of codepoints in the sequence
// doesn't equal the size of the result array.
CharArrayBuilder builder =
new CharArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
int i=0;
for(;i<initialElements.length;i++) {
builder.appendCodepoint((char) initialElements[i]);
}
Iterator<? extends ceylon.language.Character> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendCodepoint(((ceylon.language.Character) o).codePoint);
}
return builder.build();
}
public static char[]
toCharArray(ceylon.language.List<? extends ceylon.language.Character> sequence,
int... initialElements) {
return toCharArray((ceylon.language.Iterable<? extends ceylon.language.Character, ?>)sequence, initialElements);
}
@SuppressWarnings("unchecked")
public static int[]
toCodepointArray(ceylon.language.Iterable<? extends ceylon.language.Character, ?> sequence,
int... initialElements) {
if (sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.Character> list =
(ceylon.language.List<? extends ceylon.language.Character>)sequence;
return toCodepointArray(list, initialElements);
}
IntArrayBuilder builder =
new IntArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
builder.appendArray(initialElements);
Iterator<? extends ceylon.language.Character> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendInt(((ceylon.language.Character) o).codePoint);
}
return builder.build();
}
public static int[]
toCodepointArray(ceylon.language.List<? extends ceylon.language.Character> list,
int... initialElements) {
if (list == null)
return initialElements;
int i=initialElements.length;
int[] ret = new int[toInt(list.getSize() + i)];
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends ceylon.language.Character> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = ((ceylon.language.Character)o).intValue();
}
return ret;
}
@SuppressWarnings("unchecked")
public static java.lang.String[]
toJavaStringArray(ceylon.language.Iterable<? extends ceylon.language.String, ?> sequence,
java.lang.String... initialElements) {
if (sequence instanceof ceylon.language.List) {
ceylon.language.List<? extends ceylon.language.String> list =
(ceylon.language.List<? extends ceylon.language.String>) sequence;
return toJavaStringArray(list, initialElements);
}
StringArrayBuilder builder =
new StringArrayBuilder(initialElements.length+INIT_ARRAY_SIZE);
builder.appendArray(initialElements);
Iterator<? extends ceylon.language.String> iterator = sequence.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendString(((ceylon.language.String)o).value);
}
return builder.build();
}
public static java.lang.String[]
toJavaStringArray(ceylon.language.List<? extends ceylon.language.String> list,
java.lang.String... initialElements) {
if (list == null)
return initialElements;
int i=initialElements.length;
java.lang.String[] ret = new java.lang.String[toInt(list.getSize() + i)];
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends ceylon.language.String> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = ((ceylon.language.String) o).toString();
}
return ret;
}
@SuppressWarnings("unchecked")
public static <T> T[] toArray(ceylon.language.List<? extends T> sequence,
T[] ret, T... initialElements) {
if (sequence == null)
return initialElements;
int i=initialElements.length;
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends T> iterator = sequence.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = (T)o;
}
return ret;
}
@SuppressWarnings("unchecked")
public static <T> T[] toArray(ceylon.language.Iterable<? extends T, ?> iterable,
java.lang.Class<T> klass, T... initialElements) {
if (iterable == null) {
return initialElements;
}
T[] ret;
int size = fastIterableSize(iterable);
if (size != -1) {
ret = (T[]) java.lang.reflect.Array.newInstance(klass,
size + initialElements.length);
if (initialElements.length != 0) {
// fast copy of list
System.arraycopy(initialElements, 0, ret, 0,
initialElements.length);
}
fillArray(ret, initialElements.length, iterable);
} else {
ReflectingObjectArrayBuilder<T> builder =
new ReflectingObjectArrayBuilder<T>
(initialElements.length+INIT_ARRAY_SIZE, klass);
builder.appendArray(initialElements);
Iterator<? extends T> iterator = iterable.iterator();
Object o;
while (!((o = iterator.next()) instanceof Finished)) {
builder.appendRef((T) o);
}
ret = builder.build();
}
return ret;
}
@SuppressWarnings("unchecked")
public static <T> T[] toArray(ceylon.language.List<? extends T> list,
java.lang.Class<T> klass, T... initialElements) {
if (list == null)
return initialElements;
int i=initialElements.length;
T[] ret = (T[]) java.lang.reflect.Array.newInstance(klass,
toInt(list.getSize() + i));
System.arraycopy(initialElements, 0, ret, 0, i);
Iterator<? extends T> iterator = list.iterator();
Object o;
while ((o = iterator.next()) != finished_.get_()) {
ret[i++] = (T)o;
}
return ret;
}
public static <T> T checkNull(T t) {
if(t == null)
throw new AssertionError("null value returned from native call not assignable to Object");
return t;
}
/**
* Generates a default message for when a Throwable lacks a non-null
* message of its own. This can only happen for non-Ceylon throwable types,
* but due to type erasure it's not possible to know at a catch site which
* whether you have a Ceylon throwable
*/
public static String throwableMessage(java.lang.Throwable t) {
String message = t.getMessage();
if (message == null) {
java.lang.Throwable c = t.getCause();
if (c != null) {
message = c.getMessage();
} else {
message = "";
}
}
return message;
}
/**
* Return a {@link Sequential} wrapping the given elements
* (subsequent changes to the array will be visible in
* the returned {@link Sequential}).
* @param $reifiedT The reified type parameter
* @param elements The elements
* @return A Sequential
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static <T> Sequential<T>
sequentialWrapper(TypeDescriptor $reifiedT, T[] elements) {
if (elements.length == 0) {
return (Sequential) empty_.get_();
}
return new Tuple<T,T,Sequential<? extends T>>($reifiedT, elements);
}
/**
* <p>Return a {@link Sequential Sequential<String>} wrapping the
* given {@code java.lang.String[]} elements
* (subsequent changes to the array will be visible in
* the returned {@link Sequential}).</p>
*
* <p>Used to obtain a {@code Sequential<String>} from a {@code java.lang.String[]}
* obtained from an annotation.</p>
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static Sequential<? extends ceylon.language.String>
sequentialWrapperBoxed(java.lang.String[] elements) {
if (elements.length == 0) {
return (Sequential) empty_.get_();
}
int total = elements.length;
java.lang.Object[] newArray = new java.lang.Object[total];
int i = 0;
for(java.lang.String element : elements) {
newArray[i++] = ceylon.language.String.instance(element);
}
return new Tuple(ceylon.language.String.$TypeDescriptor$, newArray);
}
/**
* <p>Return a {@link Sequential Sequential<Integer>} wrapping the
* given {@code long[]} elements
* (subsequent changes to the array will be visible in
* the returned {@link Sequential}).</p>
*
* <p>Used to obtain a {@code Sequential<Integer>} from a {@code long[]}
* obtained from an annotation.</p>
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static Sequential<? extends ceylon.language.Integer>
sequentialWrapperBoxed(long[] elements) {
if (elements.length == 0) {
return (Sequential)empty_.get_();
}
int total = elements.length;
java.lang.Object[] newArray = new java.lang.Object[total];
int i = 0;
for(long element : elements) {
newArray[i++] = ceylon.language.Integer.instance(element);
}
return new Tuple(ceylon.language.Integer.$TypeDescriptor$, newArray);
}
/**
* <p>Return a {@link Sequential Sequential<Character>} wrapping the
* given {@code int[]} elements
* (subsequent changes to the array will be visible in
* the returned {@link Sequential}).</p>
*
* <p>Used to obtain a {@code Sequential<Character>} from a {@code int[]}
* obtained from an annotation.</p>
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static Sequential<? extends ceylon.language.Character>
sequentialWrapperBoxed(int[] elements) {
if (elements.length == 0) {
return (Sequential)empty_.get_();
}
int total = elements.length;
java.lang.Object[] newArray = new java.lang.Object[total];
int i = 0;
for(int element : elements) {
newArray[i++] = ceylon.language.Character.instance(element);
}
return new Tuple(ceylon.language.Character.$TypeDescriptor$, newArray);
}
/**
* <p>Return a {@link Sequential Sequential<Boolean>} wrapping the
* given {@code boolean[]} elements
* (subsequent changes to the array will be visible in
* the returned {@link Sequential}).</p>
*
* <p>Used to obtain a {@code Sequential<Boolean>} from a {@code boolean[]}
* obtained from an annotation.</p>
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static Sequential<? extends ceylon.language.Boolean>
sequentialWrapperBoxed(boolean[] elements) {
if (elements.length == 0) {
return (Sequential)empty_.get_();
}
int total = elements.length;
java.lang.Object[] newArray = new java.lang.Object[total];
int i = 0;
for(boolean element : elements) {
newArray[i++] = ceylon.language.Boolean.instance(element);
}
return new Tuple(ceylon.language.Boolean.$TypeDescriptor$, newArray);
}
/**
* <p>Return a {@link Sequential Sequential<Float>} wrapping the
* given {@code double[]} elements
* (subsequent changes to the array will be visible in
* the returned {@link Sequential}).</p>
*
* <p>Used to obtain a {@code Sequential<String>} from a {@code double[]}
* obtained from an annotation.</p>
*/
@SuppressWarnings({"unchecked","rawtypes"})
public static Sequential<? extends ceylon.language.Float>
sequentialWrapperBoxed(double[] elements) {
if (elements.length == 0) {
return (Sequential)empty_.get_();
}
int total = elements.length;
java.lang.Object[] newArray = new java.lang.Object[total];
int i = 0;
for(double element : elements) {
newArray[i++] = ceylon.language.Float.instance(element);
}
return new Tuple(ceylon.language.Float.$TypeDescriptor$, newArray);
}
/**
* Return {@link empty_#getEmpty$ empty} or an {@link ArraySequence}
* wrapping the given elements, depending on whether the given array
* and varargs are empty
* @param rest The elements at the end of the sequence
* @param elements the elements at the start of the sequence
* @return A Sequential
*/
@SuppressWarnings({"unchecked"})
public static <T> Sequential<? extends T>
sequentialCopy(TypeDescriptor $reifiedT, Sequential<? extends T> rest,
T... elements) {
return sequentialCopy($reifiedT, 0,
elements.length, elements, rest);
}
/**
* Returns a Sequential made by concatenating the {@code length} elements
* of {@code elements} starting from {@code state} with the elements of
* {@code rest}: <code> {*elements[start:length], *rest}</code>.
*
* <strong>This method does not copy {@code elements} unless it has to</strong>
*/
@SuppressWarnings("unchecked")
public static <T> Sequential<? extends T> sequentialCopy(
TypeDescriptor $reifiedT,
int start, int length, T[] elements,
Sequential<? extends T> rest) {
if (length == 0) {
if(rest.getEmpty()) {
return (Sequential<T>)empty_.get_();
}
return rest;
}
// elements is not empty
if(rest.getEmpty()) {
return new ObjectArrayIterable<T>($reifiedT, elements)
.skip(start).take(length).sequence();
}
// we have both, let's find the total size
int total = toInt(rest.getSize() + length);
java.lang.Object[] newArray = new java.lang.Object[total];
System.arraycopy(elements, start, newArray, 0, length);
Iterator<? extends T> iterator = rest.iterator();
int i = length;
for(Object elem; (elem = iterator.next()) != finished_.get_(); i++) {
newArray[i] = elem;
}
return new ObjectArrayIterable<T>($reifiedT, (T[])newArray).sequence();
}
/**
* <p>Equivalent to the Ceylon {@code sequential(iterable) else []}, this
* converts an {@code Iterable} to a {@code Sequential} without calling
* {@code Iterable.sequence()}.</p>
*
* <p>This is used for spread arguments in
* tuple literals: {@code [*foo]}</p>
* a
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Sequential sequentialOf(TypeDescriptor reified$Element,
final Iterable iterable) {
Object result = sequence_.sequence(reified$Element,
Null.$TypeDescriptor$,
iterable);
if (result == null) {
return (Sequential)empty_.get_();
}
return (Sequential)result;
}
/**
* Returns a runtime exception. To be used by implementors
* of mixin methods used to access super-interfaces $impl fields
* for final classes that don't and will never need them
*/
public static RuntimeException makeUnimplementedMixinAccessException() {
return new RuntimeException("Internal error: should never be called");
}
/**
* Specialised version of Tuple.spanFrom for when the
* typechecker determines that it can do better than the
* generic one that returns a Sequential. Here we return
* a Tuple, although our type signature hides this.
*/
public static Sequential<?> tuple_spanFrom(Ranged<?,?,?> tuple,
ceylon.language.Integer index) {
Sequential<?> seq = (Sequential<?>)tuple;
long i = index.longValue();
while(i-- > 0) {
seq = seq.getRest();
}
return seq;
}
/** Called to initialize an {@code BooleanArray} when one is instantiated */
public static boolean[] fillArray(boolean[] array, boolean val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize a {@code ByteArray} when one is instantiated */
public static byte[] fillArray(byte[] array, byte val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize an {@code ShortArray} when one is instantiated */
public static short[] fillArray(short[] array, short val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize an {@code IntArray} when one is instantiated */
public static int[] fillArray(int[] array, int val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize a {@code LongArray} when one is instantiated */
public static long[] fillArray(long[] array, long val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize a {@code FloatArray} when one is instantiated */
public static float[] fillArray(float[] array, float val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize a {@code DoubleArray} when one is instantiated */
public static double[] fillArray(double[] array, double val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize a {@code CharArray} when one is instantiated */
public static char[] fillArray(char[] array, char val) {
Arrays.fill(array, val);
return array;
}
/** Called to initialize an {@code ObjectArray<T>} when one it instantiated */
public static <T> T[] fillArray(T[] array, T val) {
Arrays.fill(array, val);
return array;
}
@SuppressWarnings("unchecked")
public static <T> T[] makeArray(TypeDescriptor $reifiedElement, int size) {
return (T[]) java.lang.reflect.Array.newInstance($reifiedElement.getArrayElementClass(), size);
}
@SuppressWarnings("unchecked")
public static <T> T[] makeArray(TypeDescriptor $reifiedElement, int... dimensions) {
return (T[]) java.lang.reflect.Array.newInstance($reifiedElement.getArrayElementClass(), dimensions);
}
/**
* Returns a runtime exception. To be used by implementors
* of Java array methods used to make sure they are never
* called
*/
public static RuntimeException makeJavaArrayWrapperException() {
return new RuntimeException("Internal error: should never be called");
}
/**
* Throws an exception without having to declare it. This
* uses a Ceylon helper that does this because Ceylon does
* not have checked exceptions. This is merely to avoid a
* javac check wrt. checked exceptions.
* Stef tried using Unsafe.throwException() but
* Unsafe.getUnsafe() throws if we have a ClassLoader, and
* the only other way is using reflection to get to it,
* which starts to smell real bad when we can just use a
* Ceylon helper.
*/
public static void rethrow(final Throwable t) {
ceylon.language.impl.rethrow_.rethrow(t);
}
/**
* Null-safe equals.
*/
public static boolean eq(Object a, Object b) {
if(a == null)
return b == null;
if(b == null)
return false;
return a.equals(b);
}
/**
* Applies the given function to the given arguments. The
* argument types are assumed to be correct and will not
* be checked. This method will properly deal with variadic
* functions. The arguments are expected to be spread in the
* given sequential, even in the case of variadic functions,
* which means that there will be no spreading of any
* Sequential instance in the given arguments. On the
* contrary, a portion of the given arguments may be packaged
* into a Sequential if the given function is variadic.
*
* @param function the function to apply
* @param arguments the argument values to pass to the function
* @return the function's return value
*/
public static <Return> Return
apply(Callable<? extends Return> function,
Sequential<? extends Object> arguments) {
int variadicParameterIndex = function.$getVariadicParameterIndex$();
switch (toInt(arguments.getSize())) {
case 0:
// even if the function is variadic it will overload $call so we're good
return function.$call$();
case 1:
// if the first param is variadic, just pass the sequence along
if(variadicParameterIndex == 0)
return function.$callvariadic$(arguments);
return function.$call$(arguments.getFromFirst(0));
case 2:
switch(variadicParameterIndex) {
// pass the sequence along
case 0: return function.$callvariadic$(arguments);
// extract the first, pass the rest
case 1: return function.$callvariadic$(arguments.getFromFirst(0),
(Sequential<?>)arguments.spanFrom(Integer.instance(1)));
// no variadic param, or after we run out of elements to pass
default:
return function.$call$(arguments.getFromFirst(0),
arguments.getFromFirst(1));
}
case 3:
switch(variadicParameterIndex) {
// pass the sequence along
case 0: return function.$callvariadic$(arguments);
// extract the first, pass the rest
case 1: return function.$callvariadic$(arguments.getFromFirst(0),
(Sequential<?>)arguments.spanFrom(Integer.instance(1)));
// extract the first and second, pass the rest
case 2: return function.$callvariadic$(arguments.getFromFirst(0),
arguments.getFromFirst(1),
(Sequential<?>)arguments.spanFrom(Integer.instance(2)));
// no variadic param, or after we run out of elements to pass
default:
return function.$call$(arguments.getFromFirst(0),
arguments.getFromFirst(1),
arguments.getFromFirst(2));
}
default:
switch(variadicParameterIndex) {
// pass the sequence along
case 0: return function.$callvariadic$(arguments);
// extract the first, pass the rest
case 1: return function.$callvariadic$(arguments.getFromFirst(0),
(Sequential<?>)arguments.spanFrom(Integer.instance(1)));
// extract the first and second, pass the rest
case 2: return function.$callvariadic$(arguments.getFromFirst(0),
arguments.getFromFirst(1),
(Sequential<?>)arguments.spanFrom(Integer.instance(2)));
case 3: return function.$callvariadic$(arguments.getFromFirst(0),
arguments.getFromFirst(1),
arguments.getFromFirst(2),
(Sequential<?>)arguments.spanFrom(Integer.instance(3)));
// no variadic param
case -1:
java.lang.Object[] args = Util.toArray(arguments,
new java.lang.Object[toInt(arguments.getSize())]);
return function.$call$(args);
// we have a variadic param in there bothering us
default:
// we stuff everything before the variadic into an array
int beforeVariadic = Math.min(toInt(arguments.getSize()),
variadicParameterIndex);
boolean needsVariadic = beforeVariadic < arguments.getSize();
args = new java.lang.Object[beforeVariadic + (needsVariadic ? 1 : 0)];
Iterator<?> iterator = arguments.iterator();
java.lang.Object it;
int i=0;
while(i < beforeVariadic &&
(it = iterator.next()) != finished_.get_()) {
args[i++] = it;
}
// add the remainder as a variadic arg if required
if(needsVariadic) {
args[i] = arguments.spanFrom(Integer.instance(beforeVariadic));
return function.$callvariadic$(args);
}
return function.$call$(args);
}
}
}
@SuppressWarnings("unchecked")
public static <T> java.lang.Class<T>
getJavaClassForDescriptor(TypeDescriptor descriptor) {
if(descriptor == TypeDescriptor.NothingType
|| descriptor == ceylon.language.Object.$TypeDescriptor$
|| descriptor == ceylon.language.Anything.$TypeDescriptor$
|| descriptor == ceylon.language.Basic.$TypeDescriptor$
|| descriptor == ceylon.language.Null.$TypeDescriptor$
|| descriptor == ceylon.language.Identifiable.$TypeDescriptor$)
return (java.lang.Class<T>) Object.class;
if(descriptor instanceof TypeDescriptor.Class)
return (java.lang.Class<T>) ((TypeDescriptor.Class) descriptor).getKlass();
if(descriptor instanceof TypeDescriptor.Member)
return getJavaClassForDescriptor(((TypeDescriptor.Member) descriptor).getMember());
if(descriptor instanceof TypeDescriptor.Intersection)
return (java.lang.Class<T>) Object.class;
if(descriptor instanceof TypeDescriptor.Union) {
TypeDescriptor.Union union = (TypeDescriptor.Union) descriptor;
TypeDescriptor[] members = union.getMembers();
// special case for optional types
if(members.length == 2) {
if(members[0] == ceylon.language.Null.$TypeDescriptor$)
return getJavaClassForDescriptor(members[1]);
if(members[1] == ceylon.language.Null.$TypeDescriptor$)
return getJavaClassForDescriptor(members[0]);
}
return (java.lang.Class<T>) Object.class;
}
return (java.lang.Class<T>) Object.class;
}
public static int arrayLength(Object o) {
if (o instanceof Object[])
return ((Object[])o).length;
else if (o instanceof boolean[])
return ((boolean[])o).length;
else if (o instanceof float[])
return ((float[])o).length;
else if (o instanceof double[])
return ((double[])o).length;
else if (o instanceof char[])
return ((char[])o).length;
else if (o instanceof byte[])
return ((byte[])o).length;
else if (o instanceof short[])
return ((short[])o).length;
else if (o instanceof int[])
return ((int[])o).length;
else if (o instanceof long[])
return ((long[])o).length;
throw new ClassCastException(notArrayType(o));
}
/**
* Used by the JVM backend to get unboxed items from an Array<Integer> backing array
*/
public static long getIntegerArray(Object o, int index) {
if (o instanceof short[])
return ((short[])o)[index];
else if (o instanceof int[])
return ((int[])o)[index];
else if (o instanceof long[])
return ((long[])o)[index];
throw new ClassCastException(notArrayType(o));
}
/**
* Used by the JVM backend to get unboxed items from an Array<Float> backing array
*/
public static double getFloatArray(Object o, int index) {
if (o instanceof float[])
return ((float[])o)[index];
else if (o instanceof double[])
return ((double[])o)[index];
throw new ClassCastException(notArrayType(o));
}
/**
* Used by the JVM backend to get unboxed items from an Array<Character> backing array
*/
public static int getCharacterArray(Object o, int index) {
if (o instanceof int[])
return ((int[])o)[index];
throw new ClassCastException(notArrayType(o));
}
/**
* Used by the JVM backend to get unboxed items from an Array<Byte> backing array
*/
public static byte getByteArray(Object o, int index) {
if (o instanceof byte[])
return ((byte[])o)[index];
throw new ClassCastException(notArrayType(o));
}
/**
* Used by the JVM backend to get unboxed items from an Array<Boolean> backing array
*/
public static boolean getBooleanArray(Object o, int index) {
if (o instanceof boolean[])
return ((boolean[])o)[index];
throw new ClassCastException(notArrayType(o));
}
/**
* Used by the JVM backend to get items from an ArraySequence object. Beware: do not use that
* for Array<Object> as there's too much magic in there.
*/
public static Object getObjectArray(Object o, int index) {
if (o instanceof Object[])
return ((Object[])o)[index];
else if (o instanceof boolean[])
return ceylon.language.Boolean.instance(((boolean[])o)[index]);
else if (o instanceof float[])
return ceylon.language.Float.instance(((float[])o)[index]);
else if (o instanceof double[])
return ceylon.language.Float.instance(((double[])o)[index]);
else if (o instanceof char[])
return ceylon.language.Character.instance(((char[])o)[index]);
else if (o instanceof byte[])
return ceylon.language.Byte.instance(((byte[])o)[index]);
else if (o instanceof short[])
return ceylon.language.Integer.instance(((short[])o)[index]);
else if (o instanceof int[])
return ceylon.language.Integer.instance(((int[])o)[index]);
else if (o instanceof long[])
return ceylon.language.Integer.instance(((long[])o)[index]);
throw new ClassCastException(notArrayType(o));
}
private static String notArrayType(Object o) {
return (o == null ? "null" : o.getClass().getName()) + " is not an array type";
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Sequential<? extends java.lang.Throwable> suppressedExceptions(
@Name("exception")
@TypeInfo("ceylon.language::Exception")
final java.lang.Throwable exception) {
java.lang.Throwable[] sup = exception.getSuppressed();
if (sup.length > 0) {
return new ObjectArrayIterable<java.lang.Throwable>
(TypeDescriptor.klass(java.lang.Throwable.class), sup)
.sequence();
} else {
return (Sequential) empty_.get_();
}
}
public static <T> Sequence<T> asSequence(Sequential<T> sequential) {
if (sequential instanceof Sequence) {
return (Sequence<T>) sequential;
} else {
throw new AssertionError("Assertion failed: Sequence expected");
}
}
/**
* <p>Typecast a {@code long} to an {@code int}, or throw if the {@code long}
* cannot be safely converted.</p>
*
* <p>We need to do this:</p>
* <ul>
* <li>when creating or indexing into an array,</li>
* <li>when invoking a Java method which takes an {@code int},</li>
* <li>when assigning to a Java {@code int} field.</li>
* <ul>
* @throws ceylon.language.OverflowException
*/
public static int toInt(long value) {
if (value <= java.lang.Integer.MAX_VALUE
&& value >= java.lang.Integer.MIN_VALUE) {
return (int)value;
}
throw new OverflowException();
}
/**
* <p>Typecast a {@code long} to a {@code shot}, or throw if the {@code long}
* cannot be safely converted.</p>
*
* <p>We need to do this:</p>
* <ul>
* <li>when invoking a Java method which takes a {@code short},</li>
* <li>when assigning to a Java {@code short} field.</li>
* <ul>
* @throws ceylon.language.OverflowException
*/
public static short toShort(long value) {
if (value <= java.lang.Short.MAX_VALUE
&& value >= java.lang.Short.MIN_VALUE) {
return (short)value;
}
throw new OverflowException();
}
/**
* <p>Typecast a {@code long} to a {@code byte}, or throw if the {@code long}
* cannot be safely converted.</p>
*
* <p>We need to do this:</p>
* <ul>
* <li>when creating or indexing into an array,</li>
* <li>when invoking a Java method which takes a {@code byte},</li>
* <li>when assigning to a Java {@code byte} field.</li>
* <ul>
* @throws ceylon.language.OverflowException
*/
public static byte toByte(long value) {
if (value <= java.lang.Byte.MAX_VALUE
&& value >= java.lang.Byte.MIN_VALUE) {
return (byte)value;
}
throw new OverflowException();
}
/**
* Used during deserialization to obtain a MethodHandle used for resetting final fields.
* @param lookup The lookup on the class containing the field
* @param fieldName The name of the field whose value is to be set
* @return The method handle
* @throws ReflectiveOperationException
*/
public static MethodHandle setter(MethodHandles.Lookup lookup, String fieldName) throws ReflectiveOperationException {
// Should this be an instance method of some thing passed to the derserialize method
Field field = lookup.lookupClass().getDeclaredField(fieldName);
field.setAccessible(true);
MethodHandle handle = lookup.unreflectSetter(field);
return handle;
}
}