summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2024-07-08 17:30:58 -0400
committerBenjamin Culkin <scorpress@gmail.com>2024-07-08 17:30:58 -0400
commit9c681f38b742b26b841eb42bc19879cb90ac03de (patch)
tree6c1b9eb1971629cc3c42bae3bff9fd930d4af11c
parent6d46c473d41c6c47e6b8bd8c676d925e544bd378 (diff)
Add XML property lists
Implement support for the XML property lists that are the newer version of the ASCII ones. There are a few things that still need to be done, but all of the basics are there Next things - Allow collapsing a property list into a series of objects - Serialize both the property list and flattened objects to XML
-rw-r--r--projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java15
-rw-r--r--projects/net.wotonomy.foundation/pom.xml2
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java13
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java9
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSEither.java237
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSError.java71
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyList.java367
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java2
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSXMLPropertyList.java363
-rw-r--r--projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ReaderInputStream.java19
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java17
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java231
-rw-r--r--projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSXMLPropertyListTest.java72
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java8
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java4
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java2
-rw-r--r--projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java26
17 files changed, 1331 insertions, 127 deletions
diff --git a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java
index 4ac8b50..100800f 100644
--- a/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java
+++ b/projects/net.wotonomy.datastore/src/main/java/net/wotonomy/datastore/DataKey.java
@@ -22,13 +22,17 @@ import java.io.Serializable;
import net.wotonomy.foundation.internal.ValueConverter;
-public class DataKey implements Comparable, Serializable, Cloneable {
+/**
+ * Represents an abstract key for a piece of data
+ *
+ */
+public class DataKey implements Comparable<Object>, Serializable, Cloneable {
static final long serialVersionUID = 8421127539579065705L;
Long key;
public DataKey() {
- key = new Long(0);
+ key = 0L;
}
/**
@@ -39,18 +43,21 @@ public class DataKey implements Comparable, Serializable, Cloneable {
setKeyString(aString);
}
+ @Override
public int hashCode() {
return key.intValue();
}
public void increment() {
- key = new Long(key.longValue() + 1);
+ key = Long.valueOf(key.longValue() + 1);
}
+ @Override
public Object clone() {
return new DataKey(this.toString());
}
+ @Override
public String toString() {
return key.toString();
}
@@ -65,6 +72,7 @@ public class DataKey implements Comparable, Serializable, Cloneable {
key = parsed;
}
+ @Override
public boolean equals(Object anObject) {
if (anObject instanceof String) {
if (toString().equals(anObject)) {
@@ -76,6 +84,7 @@ public class DataKey implements Comparable, Serializable, Cloneable {
return key.equals(((DataKey) anObject).key);
}
+ @Override
public int compareTo(Object anObject) {
if (anObject instanceof String) {
if (toString().equals(anObject)) {
diff --git a/projects/net.wotonomy.foundation/pom.xml b/projects/net.wotonomy.foundation/pom.xml
index edb26be..4a347cc 100644
--- a/projects/net.wotonomy.foundation/pom.xml
+++ b/projects/net.wotonomy.foundation/pom.xml
@@ -13,7 +13,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>3.8.1</version>
+ <version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java
index 3120ad3..ca112c9 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSData.java
@@ -23,6 +23,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
/**
* A pure java implementation of NSData, which is basically a wrapper on a byte
@@ -214,6 +215,18 @@ public class NSData {
return false;
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(bytes);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return isEqual(obj);
+ }
}
/*
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java
index e3ea753..7a097e4 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSDate.java
@@ -18,6 +18,7 @@ License along with this library; if not, see http://www.gnu.org
package net.wotonomy.foundation;
+import java.time.Instant;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
@@ -49,6 +50,14 @@ public class NSDate extends Date {
}
/**
+ * Create an NSDate that represents the given instant
+ * @param inst The instant
+ */
+ public NSDate(Instant inst) {
+ super(inst.toEpochMilli());
+ }
+
+ /**
* Represents the specified number of seconds from the current date.
*/
public NSDate(double seconds) {
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSEither.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSEither.java
new file mode 100644
index 0000000..69714c2
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSEither.java
@@ -0,0 +1,237 @@
+package net.wotonomy.foundation;
+
+import java.util.*;
+import java.util.function.*;
+
+/**
+ * Represents a choice between objects of two types
+ *
+ * @author bjculkin
+ *
+ * @param <LeftType> The type that could be on the left.
+ *
+ * @param <RightType> The type that could be on the right.
+ *
+ */
+public class NSEither<LeftType, RightType> {
+ /**
+ * Create a new either with the left value occupied.
+ *
+ * @param <LeftType> The type of the left value.
+ *
+ * @param <RightType> The type of the empty right value.
+ *
+ * @param left The value to put on the left.
+ *
+ * @return An either with the left side occupied.
+ */
+ public static <LeftType, RightType> NSEither<LeftType, RightType> left(final LeftType left) {
+ return new NSEither<>(left, null);
+ }
+
+ /**
+ * Create a new either with the right value occupied.
+ *
+ * @param <LeftType> The type of the empty left value.
+ *
+ * @param <RightType> The type of the right value.
+ *
+ * @param right The value to put on the right.
+ *
+ * @return An either with the right side occupied.
+ */
+ public static <LeftType, RightType> NSEither<LeftType, RightType> right(final RightType right) {
+ return new NSEither<>(null, right);
+ }
+
+ /* The left value of the either. */
+ private LeftType leftVal;
+ /* The right value of the either. */
+ private RightType rightVal;
+ /* Whether the left value is the one filled out. */
+ private boolean isLeft;
+
+ /* Create a new either with specifed values. */
+ private NSEither(final LeftType left, final RightType right) {
+ if (left == null) {
+ rightVal = right;
+ } else {
+ leftVal = left;
+
+ isLeft = true;
+ }
+ }
+
+ /**
+ * Perform a mapping over this either.
+ *
+ * @param <NewLeft> The new left type.
+ * @param <NewRight> The new right type.
+ *
+ * @param leftFunc The function to apply if this is a left either.
+ * @param rightFunc The function to apply if this is a right either.
+ *
+ * @return A new either, containing a value transformed by the appropriate
+ * function.
+ */
+ public <NewLeft, NewRight> NSEither<NewLeft, NewRight> map(Function<LeftType, NewLeft> leftFunc,
+ Function<RightType, NewRight> rightFunc) {
+ return isLeft ? left(leftFunc.apply(leftVal)) : right(rightFunc.apply(rightVal));
+ }
+
+ /**
+ * Extract the value from this Either.
+ *
+ * @param <Common> The common type to extract.
+ *
+ * @param leftHandler The function to handle left-values.
+ * @param rightHandler The function to handle right-values.
+ *
+ * @return The result of applying the proper function.
+ */
+ public <Common> Common extract(Function<LeftType, Common> leftHandler, Function<RightType, Common> rightHandler) {
+ return isLeft ? leftHandler.apply(leftVal) : rightHandler.apply(rightVal);
+ }
+
+ /**
+ * Perform an action on this either.
+ *
+ * @param leftHandler The handler of left values.
+ * @param rightHandler The handler of right values.
+ */
+ public void pick(Consumer<LeftType> leftHandler, Consumer<RightType> rightHandler) {
+ if (isLeft)
+ leftHandler.accept(leftVal);
+ else
+ rightHandler.accept(rightVal);
+ }
+
+ /**
+ * Check if this either is left-aligned (has the left value filled, not the
+ * right value).
+ *
+ * @return Whether this either is left-aligned.
+ */
+ public boolean isLeft() {
+ return isLeft;
+ }
+
+ /**
+ * Get the left value of this either if there is one.
+ *
+ * @return An optional containing the left value, if there is one.
+ */
+ public Optional<LeftType> getLeft() {
+ return Optional.ofNullable(leftVal);
+ }
+
+ /**
+ * Get the left value of this either, or get a {@link NoSuchElementException} if
+ * there isn't one.
+ *
+ * @return The left value of this either.
+ *
+ * @throws NoSuchElementException If this either doesn't have a left value.
+ */
+ public LeftType forceLeft() {
+ if (isLeft) {
+ return leftVal;
+ }
+
+ throw new NoSuchElementException("Either has no left value, is right value");
+ }
+
+ /**
+ * Get the right value of this either if there is one.
+ *
+ * @return An optional containing the right value, if there is one.
+ */
+ public Optional<RightType> getRight() {
+ return Optional.ofNullable(rightVal);
+ }
+
+ /**
+ * Get the right value of this either, or get a {@link NoSuchElementException}
+ * if there isn't one.
+ *
+ * @return The right value of this either.
+ *
+ * @throws NoSuchElementException If this either doesn't have a right value.
+ */
+ public RightType forceRight() {
+ if (isLeft) {
+ throw new NoSuchElementException("Either has no right value, has left value");
+ }
+
+ return rightVal;
+ }
+
+ /**
+ * Change the type of the right-side of this either.
+ *
+ * Works only for left Eithers.
+ *
+ * @param <T> The new type for the right side
+ * @return The either with the new type.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> NSEither<LeftType, T> newRight() {
+ if (isLeft) return (NSEither<LeftType, T>) this;
+
+ throw new NoSuchElementException("Can't replace right type on right Either");
+ }
+
+ /**
+ * Change the type of the left-side of this either.
+ *
+ * Works only for right Eithers.
+ *
+ * @param <T> The new type for the left side
+ * @return The either with the new type.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> NSEither<T, RightType> newLeft() {
+ if (isLeft)
+ throw new NoSuchElementException("Can't replace left type on left Either");
+ return (NSEither<T, RightType>) this;
+ }
+
+ /**
+ * Collapse an Either with the same type on both sides.
+ *
+ * @param <T> The type of the either
+ * @param eth The either to collapse
+ *
+ * @return The collapsed either
+ */
+ public static <T> T collapse(NSEither<T, T> eth) {
+ Function<T, T> id = (x) -> x;
+ return eth.extract(id, id);
+ }
+ // Misc. overrides
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isLeft, leftVal, rightVal);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+
+ NSEither<?, ?> other = (NSEither<?, ?>) obj;
+
+ return isLeft == other.isLeft && Objects.equals(leftVal, other.leftVal)
+ && Objects.equals(rightVal, other.rightVal);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Either [leftVal='%s', rightVal='%s', isLeft=%s]", leftVal, rightVal, isLeft);
+ }
+}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSError.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSError.java
new file mode 100644
index 0000000..9e46b5e
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSError.java
@@ -0,0 +1,71 @@
+package net.wotonomy.foundation;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Represents an error code.
+ *
+ * @author bjculkin
+ *
+ */
+public class NSError implements Serializable {
+ private static final long serialVersionUID = 532874201592029465L;
+
+ public static final String NSWotonomyDomain = "wotonomy";
+ public static final String NSJavaDomain = "java";
+
+ public final String domain;
+ public final int error;
+
+ public final NSDictionary<String, Object> userInfo;
+
+ private String description;
+
+ private NSArray<NSError> underlyingErrors = new NSMutableArray<>();
+
+ @SuppressWarnings("unchecked")
+ public NSError(String domain, int error) {
+ this(domain, error, (NSDictionary<String, Object>) NSDictionary.EmptyDictionary);
+ }
+
+ public NSError(String domain, int error, NSDictionary<String, Object> userInfo) {
+ this.domain = domain;
+ this.error = error;
+ this.userInfo = userInfo;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public NSArray<NSError> getUnderlyingErrors() {
+ return underlyingErrors;
+ }
+
+ public void addUnderlyingError(NSError underlying) {
+ underlyingErrors.add(underlying);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(domain, error, userInfo, description);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ NSError other = (NSError) obj;
+ return Objects.equals(domain, other.domain) && error == other.error && Objects.equals(userInfo, other.userInfo)
+ && Objects.equals(description, other.description);
+ }
+}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyList.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyList.java
new file mode 100644
index 0000000..a8cbd3d
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyList.java
@@ -0,0 +1,367 @@
+package net.wotonomy.foundation;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+public abstract class NSPropertyList implements Serializable {
+ private static final long serialVersionUID = 2671697049722442864L;
+
+ public static enum Type {
+ ARRAY, DICTIONARY, STRING, DATA, DATE,
+ INTEGER, REAL, BOOL
+ }
+
+ public final Type type;
+
+ protected boolean isImmutable;
+
+ private NSPropertyList(Type type) {
+ this.type = type;
+ }
+
+ public boolean isImmutable() {
+ return isImmutable;
+ }
+
+ public void makeImmutable() {
+ this.isImmutable = true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type);
+ }
+
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ NSPropertyList other = (NSPropertyList) obj;
+ return type == other.type;
+ }
+
+ public static final class Array extends NSPropertyList {
+ private static final long serialVersionUID = 7386250174020490701L;
+
+ private NSArray<NSPropertyList> contents;
+
+ public Array(NSArray<NSPropertyList> contents) {
+ super(Type.ARRAY);
+
+ this.contents = contents;
+ }
+
+ public NSArray<NSPropertyList> getContents() {
+ return contents;
+ }
+
+ public boolean setContents(NSArray<NSPropertyList> contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Array other = (Array) obj;
+ return Objects.equals(contents, other.contents);
+ }
+ }
+
+ public static final class Dictionary extends NSPropertyList {
+ private static final long serialVersionUID = 1979462360377516540L;
+
+ private NSDictionary<java.lang.String, NSPropertyList> contents;
+
+ public Dictionary(NSDictionary<java.lang.String,NSPropertyList> retList) {
+ super(Type.DICTIONARY);
+
+ this.contents = retList;
+ }
+
+ public NSDictionary<java.lang.String, NSPropertyList> getContents() {
+ return contents;
+ }
+
+ public boolean setContents(NSDictionary<java.lang.String, NSPropertyList> contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Dictionary other = (Dictionary) obj;
+ return Objects.equals(contents, other.contents);
+ }
+ }
+
+ public static final class String extends NSPropertyList {
+ private static final long serialVersionUID = -388698351414802814L;
+
+ private java.lang.String contents;
+
+ public String(java.lang.String contents) {
+ super(Type.STRING);
+
+ this.contents = contents;
+ }
+
+ public java.lang.String getContents() {
+ return contents;
+ }
+
+ public boolean setContents(java.lang.String contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ String other = (String) obj;
+ return Objects.equals(contents, other.contents);
+ }
+ }
+
+ public static final class Data extends NSPropertyList {
+ private static final long serialVersionUID = -6866410755763823986L;
+ private NSData contents;
+
+ public Data(NSData contents) {
+ super(Type.DATA);
+
+ this.contents = contents;
+ }
+
+ public NSData getContents() {
+ return contents;
+ }
+
+ public boolean setContents(NSData contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Data other = (Data) obj;
+ return Objects.equals(contents, other.contents);
+ }
+ }
+
+ public static final class Date extends NSPropertyList {
+ private static final long serialVersionUID = 6245107872338103662L;
+
+ private NSDate contents;
+
+ public Date(NSDate contents) {
+ super(Type.DATE);
+
+ this.contents = contents;
+ }
+
+ public NSDate getContents() {
+ return contents;
+ }
+
+ public boolean setContents(NSDate contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Date other = (Date) obj;
+ return Objects.equals(contents, other.contents);
+ }
+ }
+
+ public static final class Integer extends NSPropertyList {
+ private static final long serialVersionUID = -6375080842293791774L;
+
+ private int contents;
+
+ public Integer(int contents) {
+ super(Type.INTEGER);
+
+ this.contents = contents;
+ }
+
+ public int getContents() {
+ return contents;
+ }
+
+ public boolean setContents(int contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Integer other = (Integer) obj;
+ return contents == other.contents;
+ }
+ }
+
+ public static final class Real extends NSPropertyList {
+ private static final long serialVersionUID = -4548471713243500294L;
+
+ private double contents;
+
+ public Real(double contents) {
+ super(Type.REAL);
+
+ this.contents = contents;
+ }
+
+ public double getContents() {
+ return contents;
+ }
+
+ public boolean setContents(double contents) {
+ if (this.isImmutable) return false;
+
+ this.contents = contents;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(contents);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Real other = (Real) obj;
+ return Double.doubleToLongBits(contents) == Double.doubleToLongBits(other.contents);
+ }
+ }
+
+ public static final class Bool extends NSPropertyList {
+ private static final long serialVersionUID = 1169221814850684398L;
+ private boolean bool;
+
+ public Bool(boolean val) {
+ super(Type.BOOL);
+ }
+
+ public boolean getValue() {
+ return bool;
+ }
+
+ public boolean setValue(boolean bool) {
+ if (this.isImmutable) return false;
+
+ this.bool = bool;
+ return true;
+ }
+ }
+}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java
index b819662..01a0445 100644
--- a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSPropertyListSerialization.java
@@ -3,8 +3,6 @@ package net.wotonomy.foundation;
/**
* Class for serializing/unserializing property lists in the .plist format
- *
- *
*/
public class NSPropertyListSerialization {
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSXMLPropertyList.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSXMLPropertyList.java
new file mode 100644
index 0000000..6881d71
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSXMLPropertyList.java
@@ -0,0 +1,363 @@
+package net.wotonomy.foundation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.util.Base64;
+import java.util.Base64.Decoder;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.*;
+import org.xml.sax.SAXException;
+
+import net.wotonomy.foundation.internal.ReaderInputStream;
+import net.wotonomy.foundation.internal.WotonomyException;
+
+/**
+ * Allows reading/writing property lists in the newer XML format instead of
+ * the older text-based one.
+ *
+ * @author bjculkin
+ *
+ */
+public class NSXMLPropertyList {
+ public static enum ErrorCodes {
+ INVALID_ROOT("Invalid root element, must be <plist>"),
+ BAD_PLIST_CHILD_COUNT("<%s> must have one child element", 1),
+ BAD_PLIST_CHILD("child of <%s> must be a %s"),
+ UNKNOWN_NODE_TYPE("unknown node type %s", 1),
+ INVALID_NUM("'%s' is not a valid %s", 2),
+ BAD_COLL_ITEM("Encountered error while parsing %s", 1),
+ MISSING_MAP_KEY("encountered a <%s> while parsing a map, expected <key>", 1);
+
+ public final String desc;
+ public final int numFormatArgs;
+
+ private ErrorCodes(String desc) {
+ this(desc, 0);
+ }
+
+ private ErrorCodes(String desc, int numFormatArgs) {
+ this.desc = desc;
+ this.numFormatArgs = numFormatArgs;
+ }
+ }
+
+ public static enum ImmutabilityType {
+ Immutable, MutableContainers, MutableContainersAndLeaves
+ }
+ /**
+ * Parse a property list from a given string, with the property list
+ * being immutable.
+ *
+ * @param s The string to parse the property list from
+ * @return The immutable property list
+ */
+ public static NSEither<NSPropertyList, NSError> propertyListFromString(String s) {
+ return propertyListFromString(s, ImmutabilityType.Immutable);
+ }
+
+ public static NSEither<NSPropertyList, NSError> propertyListFromString(String s, ImmutabilityType immutable) {
+ StringReader sReader = new StringReader(s);
+ ReaderInputStream inp = new ReaderInputStream(sReader);
+ return propertyListFromStream(inp, immutable);
+ }
+
+ public static NSEither<NSPropertyList, NSError> propertyListFromStream(InputStream inp) {
+ return propertyListFromStream(inp, ImmutabilityType.Immutable);
+ }
+
+ public static NSEither<NSPropertyList, NSError> propertyListFromStream(InputStream inp, ImmutabilityType immutable) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ // TODO allow attaching comments to each element
+ factory.setIgnoringComments(true);
+ DocumentBuilder fact = factory.newDocumentBuilder();
+ Document doc = fact.parse(inp);
+ Element plistRoot = doc.getDocumentElement();
+ plistRoot.normalize();
+
+ if (!plistRoot.getTagName().equals("plist")) {
+ return createError(ErrorCodes.INVALID_ROOT);
+ }
+
+ NodeList children = plistRoot.getChildNodes();
+ // TODO this needs to be adjusted to allow comments to exist
+ if (children.getLength() != 1) {
+ return createError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "plist");
+ }
+
+ Node initial = children.item(0);
+ if (initial.getNodeType() != Node.ELEMENT_NODE) {
+ return createError(ErrorCodes.BAD_PLIST_CHILD, "plist", "tag");
+ }
+
+ return parsePlistValue(initial, immutable);
+ } catch (ParserConfigurationException pcex) {
+ throw new WotonomyException("Failed to create parser", pcex);
+ } catch (SAXException saxex) {
+ throw new RuntimeException("Failed to read XML", saxex);
+ } catch (IOException ioex) {
+ throw new RuntimeException("Error parsing XML", ioex);
+ }
+ }
+
+ private static NSEither<NSPropertyList, NSError> parsePlistValue(Node nod, ImmutabilityType immutable) {
+ String initNodeName = nod.getNodeName();
+ switch(initNodeName) {
+ case "array":
+ return arrayFromNode(nod, immutable);
+ case "dict":
+ return dictFromNode(nod, immutable);
+ case "string": {
+ NodeList stringKid = nod.getChildNodes();
+ if (stringKid.getLength() != 1) return createError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "string");
+ Node text = stringKid.item(0);
+ if (text.getNodeType() != Node.TEXT_NODE) return createError(ErrorCodes.BAD_PLIST_CHILD, "string", "text");
+ NSPropertyList.String ret = new NSPropertyList.String(text.getNodeValue());
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) ret.makeImmutable();
+ return NSEither.left(ret);
+ }
+
+ case "data": {
+ Decoder decoder = Base64.getDecoder();
+ NodeList stringKid = nod.getChildNodes();
+ if (stringKid.getLength() != 1) return createError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "data");
+ Node text = stringKid.item(0);
+ if (text.getNodeType() != Node.TEXT_NODE) return createError(ErrorCodes.BAD_PLIST_CHILD, "data", "text");
+ String raw = text.getNodeValue();
+ NSData dat = new NSData(decoder.decode(raw));
+ NSPropertyList.Data ret = new NSPropertyList.Data(dat);
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) ret.makeImmutable();
+ return NSEither.left(ret);
+ }
+ case "date": {
+ // TODO determine what the correct default date format is
+ // Believe it is ISO_INSTANT from the documentation I have read
+ DateTimeFormatter dateFmt = DateTimeFormatter.ISO_INSTANT;
+ NamedNodeMap attributes = nod.getAttributes();
+ Node formatNode = attributes.getNamedItem("format");
+ // Because we got it from the attribute map, it has to be
+ // an attribute
+ if (formatNode != null) {
+ Attr formatAttr = (Attr) formatNode;
+ String format = formatAttr.getValue();
+ dateFmt = DateTimeFormatter.ofPattern(format);
+ }
+
+ // TODO abstract this chunk into a method
+ NodeList stringKid = nod.getChildNodes();
+ if (stringKid.getLength() != 1) return createError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "date");
+ Node text = stringKid.item(0);
+ if (text.getNodeType() != Node.TEXT_NODE) return createError(ErrorCodes.BAD_PLIST_CHILD, "date", "text");
+ String val = text.getNodeValue();
+
+ TemporalAccessor tempDate = dateFmt.parse(val);
+ Instant inst = Instant.from(tempDate);
+
+ NSPropertyList.Date ret = new NSPropertyList.Date(new NSDate(inst));
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) ret.makeImmutable();
+ return NSEither.left(ret);
+ }
+ case "integer": {
+ NodeList stringKid = nod.getChildNodes();
+ if (stringKid.getLength() != 1) return createError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "integer");
+ Node text = stringKid.item(0);
+ if (text.getNodeType() != Node.TEXT_NODE) return createError(ErrorCodes.BAD_PLIST_CHILD, "integer", "text");
+ String val = text.getNodeValue();
+
+ try {
+ int ret = Integer.parseInt(val);
+
+ NSPropertyList.Integer res = new NSPropertyList.Integer(ret);
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) res.makeImmutable();
+ return NSEither.left(res);
+ } catch (NumberFormatException nfex) {
+ return createError(ErrorCodes.INVALID_NUM, val, "integer");
+ }
+ }
+ case "real": {
+ NodeList stringKid = nod.getChildNodes();
+ if (stringKid.getLength() != 1) return createError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "real");
+ Node text = stringKid.item(0);
+ if (text.getNodeType() != Node.TEXT_NODE) return createError(ErrorCodes.BAD_PLIST_CHILD, "real", "text");
+ String val = text.getNodeValue();
+
+ try {
+ double ret = Double.parseDouble(val);
+
+ NSPropertyList.Real res = new NSPropertyList.Real(ret);
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) res.makeImmutable();
+ return NSEither.left(res);
+ } catch (NumberFormatException nfex) {
+ return createError(ErrorCodes.INVALID_NUM, val, "double");
+ }
+ }
+ case "true": {
+ NSPropertyList.Bool res = new NSPropertyList.Bool(true);
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) res.makeImmutable();
+ return NSEither.left(res);
+ }
+ case "false": {
+ NSPropertyList.Bool res = new NSPropertyList.Bool(false);
+ if (immutable != ImmutabilityType.MutableContainersAndLeaves) res.makeImmutable();
+ return NSEither.left(res);
+ }
+ default:
+ return createError(ErrorCodes.UNKNOWN_NODE_TYPE, initNodeName);
+ }
+ }
+
+ private static NSEither<NSPropertyList, NSError> dictFromNode(Node nod, ImmutabilityType immutable) {
+ NodeList lst = nod.getChildNodes();
+ int numChild = lst.getLength();
+
+ boolean hasError = false;
+ NSDictionary<String, NSPropertyList> retDict = new NSMutableDictionary<>();
+ NSError retError = createRawError(ErrorCodes.BAD_COLL_ITEM, "dictionary");
+
+ for (int i = 0; i < numChild; i++) {
+ Node kid = lst.item(i);
+ short typ = kid.getNodeType();
+ if (typ == Node.COMMENT_NODE || typ == Node.PROCESSING_INSTRUCTION_NODE) continue;
+
+ if (typ != Node.ELEMENT_NODE) {
+ hasError = true;
+ // Skip over the corresponding value, since we don't have a key for it
+ i++;
+ retError.addUnderlyingError(createRawError(ErrorCodes.BAD_PLIST_CHILD, "dict", "tag"));
+ continue;
+ }
+
+ // First, grab the key, then we can handle the value
+ if (!kid.getNodeName().equals("key")) {
+ hasError = true;
+ // Skip over the corresponding value, since we don't have a key for it
+ i++;
+ retError.addUnderlyingError(createRawError(ErrorCodes.MISSING_MAP_KEY, kid.getNodeName()));
+ continue;
+ }
+
+ NodeList stringKid = kid.getChildNodes();
+
+ if (stringKid.getLength() != 1) {
+ hasError = true;
+ // Skip over the corresponding value, since we don't have a key for it
+ i++;
+ retError.addUnderlyingError(createRawError(ErrorCodes.BAD_PLIST_CHILD_COUNT, "key"));
+ continue;
+ }
+
+ Node text = stringKid.item(0);
+
+ if (text.getNodeType() != Node.TEXT_NODE) {
+ hasError = true;
+ // Skip over the corresponding value, since we don't have a key for it
+ i++;
+ retError.addUnderlyingError(createRawError(ErrorCodes.BAD_PLIST_CHILD, "key", "text"));
+ continue;
+ }
+
+ String key = text.getNodeValue();
+ i++;
+
+ kid = lst.item(i);
+ typ = kid.getNodeType();
+ if (typ == Node.COMMENT_NODE || typ == Node.PROCESSING_INSTRUCTION_NODE) continue;
+
+ if (typ != Node.ELEMENT_NODE) {
+ hasError = true;
+ retError.addUnderlyingError(createRawError(ErrorCodes.BAD_PLIST_CHILD, "array", "tag"));
+ continue;
+ }
+
+ var res = parsePlistValue(kid, immutable);
+ if (res.isLeft()) {
+ retDict.put(key, res.forceLeft());
+ } else {
+ hasError = true;
+ retError.addUnderlyingError(res.forceRight());
+ }
+ }
+
+
+ if (hasError) {
+ return NSEither.right(retError);
+ } else {
+ NSPropertyList.Dictionary res;
+ if (immutable == ImmutabilityType.Immutable) {
+ res = new NSPropertyList.Dictionary(new NSDictionary<>(retDict));
+ res.makeImmutable();
+ } else {
+ res = new NSPropertyList.Dictionary(new NSDictionary<>(retDict));
+ }
+ return NSEither.left(res);
+ }
+ }
+
+ private static NSEither<NSPropertyList, NSError> arrayFromNode(Node nod, ImmutabilityType immutable) {
+ NodeList lst = nod.getChildNodes();
+ int numChild = lst.getLength();
+
+ boolean hasError = false;
+ NSArray<NSPropertyList> retList = new NSMutableArray<>();
+ NSError retError = createRawError(ErrorCodes.BAD_COLL_ITEM, "array");
+
+ for (int i = 0; i < numChild; i++) {
+ Node kid = lst.item(i);
+ short typ = kid.getNodeType();
+ if (typ == Node.COMMENT_NODE || typ == Node.PROCESSING_INSTRUCTION_NODE) continue;
+
+ if (typ != Node.ELEMENT_NODE) {
+ hasError = true;
+ retError.addUnderlyingError(createRawError(ErrorCodes.BAD_PLIST_CHILD, "array", "tag"));
+ continue;
+ }
+
+ var res = parsePlistValue(kid, immutable);
+ if (res.isLeft()) {
+ retList.add(res.forceLeft());
+ } else {
+ hasError = true;
+ retError.addUnderlyingError(res.forceRight());
+ }
+ }
+
+ if (hasError) {
+ return NSEither.right(retError);
+ } else {
+ NSPropertyList.Array arr;
+ if (immutable == ImmutabilityType.Immutable) {
+ arr = new NSPropertyList.Array(new NSArray<>(retList));
+ arr.makeImmutable();
+ } else {
+ arr = new NSPropertyList.Array(retList);
+ }
+ return NSEither.left(arr);
+ }
+ }
+
+ private static NSEither<NSPropertyList, NSError> createError(ErrorCodes errorCode, Object... formatArgs) {
+ NSError error = createRawError(errorCode, formatArgs);
+
+ return NSEither.right(error);
+ }
+
+ private static NSError createRawError(ErrorCodes errorCode, Object... formatArgs) {
+ if (formatArgs.length != errorCode.numFormatArgs) {
+ String fmt = "Incorrect number of format args for error code %s; got %d, expected %d";
+ String msg = String.format(fmt, errorCode.name(), formatArgs.length, errorCode.numFormatArgs);
+ throw new WotonomyException(msg);
+ }
+
+ NSError error = new NSError(NSError.NSWotonomyDomain, errorCode.ordinal());
+ error.setDescription(String.format(errorCode.desc, formatArgs));
+ return error;
+ }
+}
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ReaderInputStream.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ReaderInputStream.java
new file mode 100644
index 0000000..48f8b55
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/internal/ReaderInputStream.java
@@ -0,0 +1,19 @@
+package net.wotonomy.foundation.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+public class ReaderInputStream extends InputStream {
+ private Reader rdr;
+
+ public ReaderInputStream(Reader rdr) {
+ this.rdr = rdr;
+ }
+
+ @Override
+ public int read() throws IOException {
+ return rdr.read();
+ }
+
+}
diff --git a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java
deleted file mode 100644
index 7a2e664..0000000
--- a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/AllTests.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.wotonomy.foundation;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-public class AllTests {
-
- public static Test suite() {
- TestSuite suite = new TestSuite("Test for net.wotonomy.foundation");
- // $JUnit-BEGIN$
- suite.addTestSuite(NSArrayTest.class);
- suite.addTestSuite(NSBundleTest.class);
- // $JUnit-END$
- return suite;
- }
-
-}
diff --git a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java
index 98689dc..bcee135 100644
--- a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java
+++ b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSArrayTest.java
@@ -1,41 +1,51 @@
package net.wotonomy.foundation;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
-import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
-public class NSArrayTest extends TestCase {
+public class NSArrayTest {
Object o1, o2, o3, o4, o5;
-
+
+ @Before
public void setUp() throws Exception {
o1 = "o1";
- o2 = new Integer(2);
+ o2 = Integer.valueOf(2);
o3 = null;
o4 = "o4";
- super.setUp();
}
+ @After
public void tearDown() throws Exception {
o1 = null;
o2 = null;
o3 = null;
o4 = null;
- super.tearDown();
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.hashCode()'
*/
+ @Test
public void testHashCode() {
- NSArray array1 = new NSArray(o1);
- NSArray array2 = new NSArray(o1); // same content, same hashcode.
- NSArray array3 = new NSArray("Different");
+ NSArray<Object> array1 = new NSArray<Object>(o1);
+ NSArray<Object> array2 = new NSArray<Object>(o1); // same content, same hashcode.
+ NSArray<String> array3 = new NSArray<String>("Different");
assertNotSame(array1, array2);
assertEquals(array1.hashCode(), array2.hashCode());
assertFalse("Should have different hashcodes", array1.hashCode() == array3.hashCode());
@@ -44,9 +54,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.arrayBackedByList(List)'
*/
+ @Test
public void testArrayBackedByList() {
List<Object> list = new ArrayList<>();
- NSArray array = NSArray.arrayBackedByList(list);
+ NSArray<Object> array = NSArray.arrayBackedByList(list);
assertNotNull(array);
assertSame(list, array.list);
}
@@ -54,6 +65,7 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(List, Object)'
*/
+ @Test
public void testEmptyList() {
assertNotNull(NSArray.EmptyArray);
assertEquals(0, NSArray.EmptyArray.count());
@@ -62,9 +74,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(List, Object)'
*/
+ @Test
public void testNSArrayListObject() {
List<Object> list = new ArrayList<>();
- NSArray array = new NSArray(list, null);
+ NSArray<Object> array = new NSArray<Object>(list, null);
assertNotNull(array);
assertSame(list, array.list);
}
@@ -72,34 +85,37 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(int)'
*/
+ @Test
public void testNSArrayInt() {
- NSArray array = new NSArray(5);
+ NSArray<?> array = new NSArray<Object>(5);
assertNotNull(array);
- array = new NSArray(0);
+ array = new NSArray<Object>(0);
assertNotNull(array);
try {
- array = new NSArray(-1);
+ array = new NSArray<Object>(-1);
fail("Failed to catch IllegalArgumentException.");
} catch (IllegalArgumentException e) {
}
assertNotNull(array);
- array = new NSArray(1000);
+ array = new NSArray<Object>(1000);
assertNotNull(array);
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray()'
*/
+ @Test
public void testNSArray() {
- NSArray array = new NSArray();
+ NSArray<?> array = new NSArray<Object>();
assertNotNull(array);
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(Object)'
*/
+ @Test
public void testNSArrayObject() {
- NSArray array = new NSArray(o1);
+ NSArray<Object> array = new NSArray<Object>(o1);
assertNotNull(array);
assertEquals(1, array.count());
assertEquals(o1, array.get(0));
@@ -108,8 +124,9 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(Object)'
*/
+ @Test
public void testNSArrayObjectWithNull() {
- NSArray array = new NSArray((Object) null);
+ NSArray<Object> array = new NSArray<Object>((Object) null);
assertNotNull(array);
assertEquals(1, array.count());
assertEquals(null, array.get(0));
@@ -118,9 +135,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(Object[])'
*/
+ @Test
public void testNSArrayObjectArray() {
Object[] objects = { o1, o2, o3 };
- NSArray array = new NSArray(objects);
+ NSArray<?> array = new NSArray<Object>(objects);
assertEquals(3, array.count());
for (int i = 0; i < objects.length; i++) {
assertEquals(objects[i], array.get(i));
@@ -130,12 +148,13 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.NSArray(Collection)'
*/
+ @Test
public void testNSArrayCollection() {
ArrayList<Object> list = new ArrayList<>();
list.add(o1);
list.add(o2);
list.add(o3);
- NSArray array = new NSArray(list);
+ NSArray<Object> array = new NSArray<Object>(list);
assertNotNull(array);
assertNotSame(list, array.list);
assertEquals(3, array.count());
@@ -150,9 +169,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.arrayByAddingObject(Object)'
*/
+ @Test
public void testArrayByAddingObject() {
- NSArray array = new NSArray(o1);
- NSArray array2 = array.arrayByAddingObject(o2);
+ NSArray<Object> array = new NSArray<Object>(o1);
+ NSArray<Object> array2 = array.arrayByAddingObject(o2);
assertEquals(2, array2.count());
assertEquals(o1, array2.get(0));
assertEquals(o2, array2.get(1));
@@ -162,12 +182,13 @@ public class NSArrayTest extends TestCase {
* Test method for
* 'net.wotonomy.foundation.NSArray.arrayByAddingObjectsFromArray(Collection)'
*/
+ @Test
public void testArrayByAddingObjectsFromArray() {
- NSArray array = new NSArray(o1);
+ NSArray<Object> array = new NSArray<Object>(o1);
List<Object> list = new ArrayList<>();
list.add(o2);
list.add(o3);
- NSArray array2 = array.arrayByAddingObjectsFromArray(list);
+ NSArray<Object> array2 = array.arrayByAddingObjectsFromArray(list);
assertEquals(3, array2.count());
assertEquals(o1, array2.get(0));
assertEquals(o2, array2.get(1));
@@ -178,17 +199,19 @@ public class NSArrayTest extends TestCase {
* Test method for
* 'net.wotonomy.foundation.NSArray.componentsJoinedByString(String)'
*/
+ @Test
public void testComponentsJoinedByString() {
Object[] objects = { o1, o2, o3 };
- NSArray array = new NSArray(objects);
+ NSArray<?> array = new NSArray<Object>(objects);
assertEquals("o1, 2, null", array.componentsJoinedByString(", "));
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.containsObject(Object)'
*/
+ @Test
public void testContainsObject() {
- NSArray array = new NSArray(o1);
+ NSArray<Object> array = new NSArray<Object>(o1);
assertTrue(array.contains(o1));
assertFalse(array.contains(o2));
}
@@ -197,22 +220,24 @@ public class NSArrayTest extends TestCase {
* Test method for
* 'net.wotonomy.foundation.NSArray.firstObjectCommonWithArray(Collection)'
*/
+ @Test
public void testFirstObjectCommonWithArray() {
ArrayList<Object> list = new ArrayList<>();
list.add(o2);
list.add(o3);
list.add(o4);
- NSArray array = new NSArray(new Object[] { o1, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o3, o4 });
assertEquals(o3, array.firstObjectCommonWithArray(list));
}
/*
* Test method for 'net.wotonomy.foundation.NSArray.isEqualToArray(List)'
*/
+ @Test
public void testEqualsAndIsEqualToArray() {
- NSArray array1 = new NSArray(o1);
- NSArray array2 = new NSArray(o1); // same content, same hashcode.
- NSArray array3 = new NSArray(o2);
+ NSArray<Object> array1 = new NSArray<>(o1);
+ NSArray<Object> array2 = new NSArray<>(o1); // same content, same hashcode.
+ NSArray<Object> array3 = new NSArray<>(o2);
assertNotSame(array1, array2);
assertTrue("Should be equal", array1.equals(array2));
assertTrue("Should be equal", array1.isEqualToArray(array2));
@@ -223,8 +248,9 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.lastObject()'
*/
+ @Test
public void testLastObject() {
- NSArray array = new NSArray(new Object[] { o1, o2 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2 });
assertEquals(o2, array.lastObject());
// test for empty array
assertEquals(null, NSArray.EmptyArray.lastObject());
@@ -234,9 +260,10 @@ public class NSArrayTest extends TestCase {
* Test method for 'net.wotonomy.foundation.NSArray.subarrayWithRange(NSRange)'
* TODO: Add ranges that exceed the size of the array.
*/
+ @Test
public void testSubarrayWithRange() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
- NSArray subarray = array.subarrayWithRange(new NSRange(1, 2));
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
+ NSArray<?> subarray = array.subarrayWithRange(new NSRange(1, 2));
assertEquals(2, subarray.count());
assertEquals(o2, subarray.get(0));
assertEquals(o3, subarray.get(1));
@@ -245,9 +272,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.objectEnumerator()'
*/
+ @Test
public void testObjectEnumerator() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
- Enumeration e = array.objectEnumerator();
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
+ Enumeration<?> e = array.objectEnumerator();
assertTrue(e.hasMoreElements());
assertEquals(o1, e.nextElement());
assertEquals(o2, e.nextElement());
@@ -258,9 +286,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.reverseObjectEnumerator()'
*/
+ @Test
public void testReverseObjectEnumerator() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
- Enumeration e = array.reverseObjectEnumerator();
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
+ Enumeration<?> e = array.reverseObjectEnumerator();
assertTrue(e.hasMoreElements());
assertEquals(o4, e.nextElement());
assertEquals(o3, e.nextElement());
@@ -271,9 +300,10 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.getObjects(Object[])'
*/
+ @Test
public void testGetObjectsObjectArray() {
Object[] oa = new Object[4];
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa);
assertEquals(o1, oa[0]);
assertEquals(o2, oa[1]);
@@ -282,18 +312,20 @@ public class NSArrayTest extends TestCase {
assertEquals(4, oa.length);
}
+ @Test
public void testGetObjectsObjectArrayWithSmallArray() {
Object[] oa = new Object[2];
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa);
assertEquals(o1, oa[0]);
assertEquals(o2, oa[1]);
assertEquals(2, oa.length);
}
+ @Test
public void testGetObjectsObjectArrayWithLargeArray() {
Object[] oa = new Object[5];
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa);
assertEquals(o1, oa[0]);
assertEquals(o2, oa[1]);
@@ -307,18 +339,20 @@ public class NSArrayTest extends TestCase {
* Test method for 'net.wotonomy.foundation.NSArray.getObjects(Object[],
* NSRange)' TODO: Try more ranges.
*/
+ @Test
public void testGetObjectsObjectArrayNSRange() {
Object[] oa = new Object[2];
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa, new NSRange(1, 2));
assertEquals(o2, oa[0]);
assertEquals(o3, oa[1]);
assertEquals(2, oa.length);
}
+ @Test
public void testGetObjectsObjectArrayNSRangeWithLargeRange() {
Object[] oa = new Object[4];
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
array.getObjects(oa, new NSRange(1, 90));
assertEquals(o2, oa[0]);
assertEquals(o3, oa[1]);
@@ -330,8 +364,9 @@ public class NSArrayTest extends TestCase {
/*
* Test method for 'net.wotonomy.foundation.NSArray.indexOfObject(Object)'
*/
+ @Test
public void testIndexOfObjectObject() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
assertEquals(0, array.indexOfObject(o1));
assertEquals(1, array.indexOfObject(o2));
assertEquals(2, array.indexOfObject(o3));
@@ -343,8 +378,9 @@ public class NSArrayTest extends TestCase {
* Test method for 'net.wotonomy.foundation.NSArray.indexOfObject(Object,
* NSRange)'
*/
+ @Test
public void testIndexOfObjectObjectNSRange() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
NSRange range = new NSRange(1, 2);
assertEquals(-1, array.indexOfObject(o1, range));
assertEquals(1, array.indexOfObject(o2, range));
@@ -355,20 +391,22 @@ public class NSArrayTest extends TestCase {
assertEquals(-1, array.indexOfObject("No Such Object"));
}
+ @Test
public void testIndexOfIdenticalObjectObject() {
- Integer i1 = new Integer(3 - 1);
- Integer i2 = new Integer(4 / 2);
- NSArray array = new NSArray(new Object[] { o1, i2, o3, o4 });
+ Integer i1 = Integer.valueOf(3 - 1);
+ Integer i2 = Integer.valueOf(4 / 2);
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, i2, o3, o4 });
assertEquals(1, array.indexOfObject(i1));
assertFalse(1 == array.indexOfIdenticalObject(i1));
assertEquals(1, array.indexOfIdenticalObject(i2));
}
+ @Test
public void testIndexOfIdenticalObjectObjectNSRange() {
- Integer i1 = new Integer(3 - 1);
- Integer i2 = new Integer(4 / 2);
+ Integer i1 = Integer.valueOf(3 - 1);
+ Integer i2 = Integer.valueOf(4 / 2);
NSRange range = new NSRange(1, 2);
- NSArray array = new NSArray(new Object[] { o1, i2, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, i2, o3, o4 });
assertEquals(1, array.indexOfObject(i1, range));
assertFalse(1 == array.indexOfIdenticalObject(i1, range));
assertEquals(1, array.indexOfIdenticalObject(i2, range));
@@ -378,8 +416,9 @@ public class NSArrayTest extends TestCase {
assertEquals(-1, array.indexOfIdenticalObject(i2, range2));
}
+ @Test
public void testObjectAtIndex() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
assertEquals(o1, array.objectAtIndex(0));
assertEquals(o2, array.objectAtIndex(1));
assertEquals(o3, array.objectAtIndex(2));
@@ -391,9 +430,10 @@ public class NSArrayTest extends TestCase {
}
}
+ @Test
public void testComponentsSeparatedByString() {
String arrayString = "word0 word1 word2 word3";
- NSArray array = NSArray.componentsSeparatedByString(arrayString, " ");
+ NSArray<?> array = NSArray.componentsSeparatedByString(arrayString, " ");
assertEquals("word0", array.objectAtIndex(0));
assertEquals("word1", array.objectAtIndex(1));
assertEquals("word2", array.objectAtIndex(2));
@@ -414,33 +454,37 @@ public class NSArrayTest extends TestCase {
* }
*/
+ @Test
public void testToString() {
- NSArray array = new NSArray(new Object[] { "o1", new Integer(1), "o3" });
+ NSArray<?> array = new NSArray<Object>(new Object[] { "o1", Integer.valueOf(1), "o3" });
assertEquals("(o1, 1, o3)", array.toString());
}
+ @Test
public void testContains() {
- NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o4 });
assertTrue("Should contain object", array.contains(o1));
assertTrue("Should contain object", array.contains(o2));
assertFalse("Should not contain object", array.contains(o3));
assertTrue("Should contain object", array.contains(o4));
}
+ @Test
public void testContainsAll() {
- NSArray array = new NSArray(new Object[] { o1, o2, o4 });
- ArrayList list = new ArrayList();
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o4 });
+ ArrayList<Object> list = new ArrayList<Object>();
list.add(o1);
list.add(o2);
assertTrue("Should have all elements of provided list.", array.containsAll(list));
- ArrayList list2 = new ArrayList();
+ ArrayList<Object> list2 = new ArrayList<Object>();
list2.add(o2);
list2.add(o3);
assertFalse("Should not have all elements of provided list.", array.containsAll(list2));
}
+ @Test
public void testGet() {
- NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o4 });
assertEquals(o1, array.get(0));
assertEquals(o2, array.get(1));
assertEquals(o4, array.get(2));
@@ -450,43 +494,49 @@ public class NSArrayTest extends TestCase {
}
}
+ @Test
public void testIndexOf() {
- NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o4 });
assertEquals(0, array.indexOf(o1));
assertEquals(1, array.indexOf(o2));
assertEquals(-1, array.indexOf(o3));
assertEquals(2, array.indexOf(o4));
}
+ @Test
public void testIsEmpty() {
- assertFalse(new NSArray(new Object[] { o1, o2, o4 }).isEmpty());
- assertTrue(new NSArray(new Object[] {}).isEmpty());
+ assertFalse(new NSArray<Object>(new Object[] { o1, o2, o4 }).isEmpty());
+ assertTrue(new NSArray<Object>(new Object[] {}).isEmpty());
}
+ @Test
public void testLastIndexOf() {
- NSArray array = new NSArray(new Object[] { o1, o4, o2, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o4, o2, o4 });
assertEquals(0, array.lastIndexOf(o1));
assertEquals(2, array.lastIndexOf(o2));
assertEquals(-1, array.lastIndexOf(o3));
assertEquals(3, array.lastIndexOf(o4));
}
+ @Test
public void testSize() {
- assertEquals(3, new NSArray(new Object[] { o1, o2, o4 }).size());
- assertEquals(1, new NSArray(new Object[] { o1 }).size());
- assertEquals(0, new NSArray(new Object[] {}).size());
+ assertEquals(3, new NSArray<Object>(new Object[] { o1, o2, o4 }).size());
+ assertEquals(1, new NSArray<Object>(new Object[] { o1 }).size());
+ assertEquals(0, new NSArray<Object>(new Object[] {}).size());
}
+ @Test
public void testToArray() {
- NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o4 });
Object[] oarray = array.toArray();
assertEquals(oarray[0], o1);
assertEquals(oarray[1], o2);
assertEquals(oarray[2], o4);
}
+ @Test
public void testToArrayObjectArray() {
- NSArray array = new NSArray(new Object[] { o1, o2, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o4 });
Object[] oa0 = new Object[3];
Object[] oa1 = array.toArray(oa0);
assertSame(oa0, oa1);
@@ -495,8 +545,9 @@ public class NSArrayTest extends TestCase {
assertEquals(oa1[2], o4);
}
+ @Test
public void testAddIntObject() {
- NSArray array = new NSArray(new Object[] { o1, o3, o4 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o3, o4 });
array.add(1, o2);
assertEquals(0, array.indexOfObject(o1));
assertEquals(1, array.indexOfObject(o2));
@@ -504,8 +555,9 @@ public class NSArrayTest extends TestCase {
assertEquals(3, array.indexOfObject(o4));
}
+ @Test
public void testAddObject() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3 });
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2, o3 });
array.add(o4);
assertEquals(0, array.indexOfObject(o1));
assertEquals(1, array.indexOfObject(o2));
@@ -513,9 +565,10 @@ public class NSArrayTest extends TestCase {
assertEquals(3, array.indexOfObject(o4));
}
+ @Test
public void testAddAllCollection() {
- NSArray array = new NSArray(new Object[] { o1, o2 });
- ArrayList list = new ArrayList();
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o2 });
+ ArrayList<Object> list = new ArrayList<Object>();
list.add(o3);
list.add(o4);
array.addAll(list);
@@ -525,9 +578,10 @@ public class NSArrayTest extends TestCase {
assertEquals(3, array.indexOfObject(o4));
}
+ @Test
public void testAddAllIntCollection() {
- NSArray array = new NSArray(new Object[] { o1, o4 });
- ArrayList list = new ArrayList();
+ NSArray<Object> array = new NSArray<Object>(new Object[] { o1, o4 });
+ ArrayList<Object> list = new ArrayList<Object>();
list.add(o2);
list.add(o3);
array.addAll(1, list);
@@ -537,23 +591,26 @@ public class NSArrayTest extends TestCase {
assertEquals(3, array.indexOfObject(o4));
}
+ @Test
public void testClear() {
- NSArray array = new NSArray(new Object[] { o1, o2 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2 });
array.clear();
assertEquals(0, array.size());
}
+ @Test
public void testIterator() {
- NSArray array = new NSArray(new Object[] { o1, o4 });
- Iterator i = array.iterator();
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o4 });
+ Iterator<?> i = array.iterator();
assertEquals(o1, i.next());
assertEquals(o4, i.next());
assertFalse(i.hasNext());
}
+ @Test
public void testListIterator() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
- ListIterator i = array.listIterator();
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
+ ListIterator<?> i = array.listIterator();
assertEquals(o1, i.next());
assertEquals(o2, i.next());
assertEquals(o3, i.next());
@@ -565,9 +622,10 @@ public class NSArrayTest extends TestCase {
assertFalse(i.hasNext());
}
+ @Test
public void testListIteratorInt() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
- ListIterator i = array.listIterator(1);
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
+ ListIterator<?> i = array.listIterator(1);
assertEquals(o2, i.next());
assertEquals(o3, i.next());
assertEquals(o4, i.next());
@@ -578,16 +636,18 @@ public class NSArrayTest extends TestCase {
assertFalse(i.hasNext());
}
+ @Test
public void testRemoveInt() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
assertEquals(o2, array.remove(1));
assertEquals(o3, array.remove(1));
assertEquals(o1, array.objectAtIndex(0));
assertEquals(o4, array.objectAtIndex(1));
}
+ @Test
public void testRemoveObject() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
assertTrue(array.remove(o2));
assertTrue(array.remove(o3));
assertFalse(array.remove("blah"));
@@ -595,9 +655,10 @@ public class NSArrayTest extends TestCase {
assertEquals(o4, array.objectAtIndex(1));
}
+ @Test
public void testRemoveAll() {
- NSArray array = new NSArray(new Object[] { o1, o2, o3, o4 });
- ArrayList list = new ArrayList();
+ NSArray<?> array = new NSArray<Object>(new Object[] { o1, o2, o3, o4 });
+ ArrayList<Object> list = new ArrayList<Object>();
list.add(o1);
list.add(o2);
array.removeAll(list);
diff --git a/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSXMLPropertyListTest.java b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSXMLPropertyListTest.java
new file mode 100644
index 0000000..0427f9e
--- /dev/null
+++ b/projects/net.wotonomy.foundation/src/test/java/net/wotonomy/foundation/NSXMLPropertyListTest.java
@@ -0,0 +1,72 @@
+package net.wotonomy.foundation;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class NSXMLPropertyListTest {
+
+ @Test
+ public void testStringParse() {
+ var res = NSXMLPropertyList.propertyListFromString("<plist><string>abc</string></plist>");
+ if (res.isLeft()) {
+ NSPropertyList val = res.forceLeft();
+ if (val.type != NSPropertyList.Type.STRING) {
+ fail("property list parsed incorrectly - got " + val.type.name() + " instead of string");
+ }
+ NSPropertyList.String castVal = (NSPropertyList.String) val;
+ assertEquals("abc", castVal.getContents());
+ } else {
+ NSError err = res.forceRight();
+ fail("failed to parse property list - " + err.getDescription());
+ }
+ }
+
+ @Test
+ public void testArrayParse() {
+ var res = NSXMLPropertyList.propertyListFromString("<plist><array><string>abc</string><string>def</string></array></plist>");
+ if (res.isLeft()) {
+ NSPropertyList val = res.forceLeft();
+ if (val.type != NSPropertyList.Type.ARRAY) {
+ fail("property list parsed incorrectly - got " + val.type.name() + " instead of array");
+ }
+ NSPropertyList.Array castVal = (NSPropertyList.Array) val;
+ NSArray<NSPropertyList> contents = castVal.getContents();
+
+ assertEquals(2, contents.size());
+ assertEquals(NSPropertyList.Type.STRING, contents.get(0).type);
+ assertEquals(NSPropertyList.Type.STRING, contents.get(1).type);
+ assertEquals("abc", ((NSPropertyList.String)contents.get(0)).getContents());
+ assertEquals("def", ((NSPropertyList.String)contents.get(1)).getContents());
+ } else {
+ NSError err = res.forceRight();
+ fail("failed to parse property list - " + err.getDescription());
+ }
+ }
+
+ @Test
+ public void testDictParse() {
+ var res = NSXMLPropertyList.propertyListFromString("<plist><dict><key>abc</key><integer>5</integer></dict></plist>");
+ if (res.isLeft()) {
+ NSPropertyList val = res.forceLeft();
+ if (val.type != NSPropertyList.Type.DICTIONARY) {
+ fail("property list parsed incorrectly - got " + val.type.name() + " instead of dictionary");
+ }
+ NSPropertyList.Dictionary castVal = (NSPropertyList.Dictionary) val;
+ NSDictionary<String, NSPropertyList> contents = castVal.getContents();
+
+ assertEquals(1, contents.size());
+ assertEquals(NSPropertyList.Type.INTEGER, contents.get("abc").type);
+ assertEquals(5, ((NSPropertyList.Integer)contents.get("abc")).getContents());
+ } else {
+ NSError err = res.forceRight();
+ StringBuilder underlyingErrors = new StringBuilder();
+ for (NSError underlyingError : err.getUnderlyingErrors()) {
+ underlyingErrors.append(underlyingError.getDescription());
+ underlyingErrors.append(", ");
+ }
+
+ fail("failed to parse property list - " + err.getDescription() + "\n - " + underlyingErrors.toString());
+ }
+ }
+}
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java
index 3512c2a..a09df1e 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DebuggingDelegate.java
@@ -101,7 +101,7 @@ public class DebuggingDelegate implements EODisplayGroup.Delegate {
* @return An NSArray containing the objects to be displayed for the objects in
* the specified list.
*/
- public NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList) {
+ public <T> NSArray<T> displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List<T> aList) {
return get("displayGroupDisplayArrayForObjects", aDisplayGroup, aList);
}
@@ -155,7 +155,7 @@ public class DebuggingDelegate implements EODisplayGroup.Delegate {
* insertion.
*/
public boolean displayGroupShouldInsertObject(EODisplayGroup aDisplayGroup, Object anObject, int anIndex) {
- return ask("displayGroupShouldInsertObject", aDisplayGroup, new Object[] { anObject, new Integer(anIndex) });
+ return ask("displayGroupShouldInsertObject", aDisplayGroup, new Object[] { anObject, Integer.valueOf(anIndex) });
}
/**
@@ -190,9 +190,9 @@ public class DebuggingDelegate implements EODisplayGroup.Delegate {
* This method is called by displayGroupDisplayArrayForObjects. This
* implementation calls report and returns a copy of the specified list.
*/
- protected NSArray get(String aTitle, EODisplayGroup aDisplayGroup, List anObjectList) {
+ protected <T> NSArray<T> get(String aTitle, EODisplayGroup aDisplayGroup, List<T> anObjectList) {
report(aTitle, aDisplayGroup, new Object[] { anObjectList });
- return new NSArray(anObjectList);
+ return new NSArray<>(anObjectList);
}
/**
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java
index e801406..c7e549c 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/DelegateAdapter.java
@@ -101,8 +101,8 @@ public class DelegateAdapter implements EODisplayGroup.Delegate {
* @return An NSArray containing the objects to be displayed for the objects in
* the specified list.
*/
- public NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList) {
- return new NSArray(aList);
+ public <T> NSArray<T> displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List<T> aList) {
+ return new NSArray<>(aList);
}
/**
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java
index 033f0a9..e2b2b11 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/EODisplayGroup.java
@@ -1653,7 +1653,7 @@ public class EODisplayGroup extends Observable implements EOObserving, EOEditing
* @return An NSArray containing the objects to be displayed for the objects in
* the specified list.
*/
- NSArray displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List aList);
+ <T> NSArray<T> displayGroupDisplayArrayForObjects(EODisplayGroup aDisplayGroup, List<T> aList);
/**
* Called by the specified display group before it attempts to change the
diff --git a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java
index e18ed3b..7755e8f 100644
--- a/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java
+++ b/projects/net.wotonomy.ui/src/main/java/net/wotonomy/ui/ObservableArray.java
@@ -36,7 +36,9 @@ import net.wotonomy.foundation.NSRange;
* probably call each other. However, EOObserverCenter will only register us
* once per object.
*/
-class ObservableArray extends NSMutableArray {
+class ObservableArray<T> extends NSMutableArray<T> {
+ private static final long serialVersionUID = 9098414040194393263L;
+
EOObserving observer;
ObservableArray(EOObserving anObserver) {
@@ -60,7 +62,7 @@ class ObservableArray extends NSMutableArray {
/**
* Adds all objects in the specified collection.
*/
- public void addObjectsFromArray(Collection aCollection) {
+ public void addObjectsFromArray(Collection<T> aCollection) {
addAll(aCollection);
}
@@ -112,7 +114,7 @@ class ObservableArray extends NSMutableArray {
/**
* Removes all objects in the specified collection from the array.
*/
- public void removeObjectsInArray(Collection aCollection) {
+ public void removeObjectsInArray(Collection<T> aCollection) {
removeAll(aCollection);
}
@@ -134,7 +136,7 @@ class ObservableArray extends NSMutableArray {
* objects are removed. If otherRange is larger than currentRange, the extra
* objects are added.
*/
- public void replaceObjectsInRange(NSRange currentRange, List otherArray, NSRange otherRange) {
+ public void replaceObjectsInRange(NSRange currentRange, List<T> otherArray, NSRange otherRange) {
if ((currentRange == null) || (otherArray == null) || (otherRange == null))
return;
@@ -183,7 +185,7 @@ class ObservableArray extends NSMutableArray {
/**
* Removes all occurences of the specified object, comparing by reference.
*/
- public void removeIdenticalObject(Object anObject) {
+ public void removeIdenticalObject(T anObject) {
EOObserverCenter.removeObserver(observer, anObject);
super.removeIdenticalObject(anObject);
}
@@ -191,32 +193,32 @@ class ObservableArray extends NSMutableArray {
/**
* Inserts the specified object into this array at the specified index.
*/
- public void insertObjectAtIndex(Object anObject, int anIndex) {
+ public void insertObjectAtIndex(T anObject, int anIndex) {
add(anIndex, anObject);
}
/**
* Replaces the object at the specified index with the specified object.
*/
- public void replaceObjectAtIndex(int anIndex, Object anObject) {
+ public void replaceObjectAtIndex(int anIndex, T anObject) {
set(anIndex, anObject);
}
/**
* Adds the specified object to the end of this array.
*/
- public void addObject(Object anObject) {
+ public void addObject(T anObject) {
add(anObject);
}
// interface List: mutators
- public void add(int index, Object element) {
+ public void add(int index, T element) {
EOObserverCenter.addObserver(observer, element);
super.add(index, element);
}
- public boolean add(Object o) {
+ public boolean add(T o) {
EOObserverCenter.addObserver(observer, o);
return super.add(o);
}
@@ -245,7 +247,7 @@ class ObservableArray extends NSMutableArray {
super.clear();
}
- public Object remove(int index) {
+ public T remove(int index) {
EOObserverCenter.removeObserver(observer, get(index));
return super.remove(index);
}
@@ -267,7 +269,7 @@ class ObservableArray extends NSMutableArray {
throw new UnsupportedOperationException();
}
- public Object set(int index, Object element) {
+ public T set(int index, T element) {
EOObserverCenter.removeObserver(observer, get(index));
EOObserverCenter.addObserver(observer, element);
return super.set(index, element);