Skip to content

Commit a6f1ca6

Browse files
committed
v1.8.2: PrettyCollections API and fixes
1 parent 33e2f45 commit a6f1ca6

File tree

9 files changed

+161
-81
lines changed

9 files changed

+161
-81
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ for a higher control compared to the EasyML Facade.
6060

6161
### Release Notes
6262

63+
Release 1.8.2
64+
- feature: added EasyML.defaultConfiguration(writer, prettyCollections)
65+
- bugfix: PrettyCollections impl for comparators
66+
67+
6368
Release 1.8.1
6469
- feature: PrettyCollections option for formatting Java Collections
6570
- bugfix: collection impl for java.util.Collections unmodifiableSequencedCollection()

easyml/src/net/sourceforge/easyml/EasyML.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
* objects.<br/>
8787
*
8888
* @author Victor Cordis ( cordis.victor at gmail.com)
89-
* @version 1.8.1
89+
* @version 1.8.2
9090
* @see XMLReader
9191
* @see XMLWriter
9292
* @since 1.0
@@ -290,7 +290,14 @@ private EasyML(Supplier<XmlPullParser> xmlPullParserProvider, boolean prettyColl
290290
}
291291
}
292292

293-
private static void defaultConfiguration(XMLWriter writer, boolean prettyCollections) {
293+
/**
294+
* Configures all default strategies to the given writer.
295+
*
296+
* @param writer to configure
297+
* @param prettyCollections true to enable pretty collections format
298+
* @see PrettyCollectionsStrategies
299+
*/
300+
public static void defaultConfiguration(XMLWriter writer, boolean prettyCollections) {
294301
final XMLWriter.StrategyRegistry<SimpleStrategy> simple = writer.getSimpleStrategies();
295302
final XMLWriter.StrategyRegistry<CompositeStrategy> composite = writer.getCompositeStrategies();
296303
// dtd: because of the primitives API, DTD are included by default in the writer:

easyml/src/net/sourceforge/easyml/XMLReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ private Object read0(Class componentType) {
925925
this.decoded.put(idAttr, newed);
926926
// init composite:
927927
final Object inited = cs.unmarshalInit(newed, this.driver, this.context);
928-
if (newed != inited) { // for features such as Java IO Serializable readResolve:
928+
if (newed != inited) { // support features such as immutable objects or Serializable readResolve:
929929
this.ensureSecurityPolicy(inited);
930930
this.decoded.put(idAttr, inited);
931931
}

easyml/src/net/sourceforge/easyml/marshalling/java/util/CollectionStrategy.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import net.sourceforge.easyml.marshalling.*;
2323

2424
import java.util.Collection;
25+
import java.util.function.Function;
2526

2627
/**
2728
* CollectionStrategy abstract class that implements the
@@ -30,7 +31,7 @@
3031
*
3132
* @param <T> target collection class
3233
* @author Victor Cordis ( cordis.victor at gmail.com)
33-
* @version 1.8.1
34+
* @version 1.8.2
3435
* @since 1.0
3536
*/
3637
public abstract class CollectionStrategy<T extends Collection> extends AbstractStrategy implements CompositeStrategy<T> {
@@ -79,18 +80,31 @@ protected void marshalElements(T target, CompositeWriter writer) {
7980
*/
8081
@Override
8182
public T unmarshalInit(T target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
83+
final String endElementName = this.name();
84+
final Function<CompositeReader, Object> unmarshalElement = unmarshalElement(target, reader, ctx);
8285
// consume root element:
8386
reader.next();
8487
// read elements:
85-
final String endElementName = this.name();
8688
while (true) {
8789
if (reader.atElementEnd() && reader.elementName().equals(endElementName)) {
8890
return target;
8991
}
90-
final Object element = reader.read();
92+
final Object element = unmarshalElement.apply(reader);
9193
if (!target.add(element)) {
9294
throw new InvalidFormatException(ctx.readerPositionDescriptor(), "adding: " + element);
9395
}
9496
}
9597
}
98+
99+
/**
100+
* Creates a function for reading an element, optionally mapping it.
101+
*
102+
* @param target optionally needed for mapping
103+
* @param reader optionally needed for mapping
104+
* @param ctx optionally needed for mapping
105+
* @return unmarshalling function
106+
*/
107+
protected Function<CompositeReader, Object> unmarshalElement(T target, CompositeReader reader, UnmarshalContext ctx) {
108+
return CompositeReader::read;
109+
}
96110
}

easyml/src/net/sourceforge/easyml/marshalling/java/util/EnumMapStrategy.java

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
import java.util.EnumMap;
2828
import java.util.Map;
2929
import java.util.Set;
30+
import java.util.function.Function;
3031

3132
/**
3233
* EnumMapStrategy class that extends the {@linkplain MapStrategy} for
3334
* the {@linkplain EnumMap}. This implementation is thread-safe.
3435
*
3536
* @author Victor Cordis ( cordis.victor at gmail.com)
36-
* @version 1.8.1
37+
* @version 1.8.2
3738
* @since 1.4.6
3839
*/
3940
public final class EnumMapStrategy extends MapStrategy<EnumMap> {
@@ -94,25 +95,13 @@ public EnumMap unmarshalNew(CompositeReader reader, UnmarshalContext ctx) throws
9495
}
9596

9697
@Override
97-
public EnumMap unmarshalInit(EnumMap target, CompositeReader reader, UnmarshalContext ctx) {
98+
protected Function<CompositeReader, Object> unmarshalKey(EnumMap target, CompositeReader reader, UnmarshalContext ctx) {
9899
final Class keyTypeCls;
99100
try {
100101
keyTypeCls = ctx.classFor(reader.elementRequiredAttribute(ATTRIBUTE_KEYTYPE));
101-
} catch (ClassNotFoundException e) {
102-
throw new InvalidFormatException(ctx.readerPositionDescriptor(), "invalid " + ATTRIBUTE_KEYTYPE + ": " + e.getMessage());
103-
}
104-
// consume root element:
105-
reader.next();
106-
// read elements:
107-
while (true) {
108-
if (reader.atElementEnd() && reader.elementName().equals(EnumMapStrategy.NAME)) {
109-
return target;
110-
}
111-
final Enum key = Enum.valueOf(keyTypeCls, reader.readString());
112-
final Object value = reader.read();
113-
if (target.put(key, value) != null) {
114-
throw new InvalidFormatException(ctx.readerPositionDescriptor(), "duplicate key: " + key);
115-
}
102+
} catch (ClassNotFoundException thrownAtUnmarshalNew) {
103+
throw new InvalidFormatException(ctx.readerPositionDescriptor(), "invalid " + ATTRIBUTE_KEYTYPE, thrownAtUnmarshalNew);
116104
}
105+
return r -> Enum.valueOf(keyTypeCls, r.readString());
117106
}
118107
}

easyml/src/net/sourceforge/easyml/marshalling/java/util/EnumSetStrategy.java

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@
1818
*/
1919
package net.sourceforge.easyml.marshalling.java.util;
2020

21-
import net.sourceforge.easyml.InvalidFormatException;
2221
import net.sourceforge.easyml.marshalling.CompositeReader;
2322
import net.sourceforge.easyml.marshalling.CompositeWriter;
2423
import net.sourceforge.easyml.marshalling.MarshalContext;
2524
import net.sourceforge.easyml.marshalling.UnmarshalContext;
2625

2726
import java.util.EnumSet;
27+
import java.util.function.Function;
2828

2929
/**
3030
* EnumSetStrategy class that extends the {@linkplain CollectionStrategy} for
3131
* the {@linkplain EnumSet}. This implementation is thread-safe.
3232
*
3333
* @author Victor Cordis ( cordis.victor at gmail.com)
34-
* @version 1.8.1
34+
* @version 1.8.2
3535
* @since 1.4.6
3636
*/
3737
public final class EnumSetStrategy extends CollectionStrategy<EnumSet> {
@@ -83,7 +83,7 @@ public String name() {
8383

8484
@Override
8585
protected void marshalAttrs(EnumSet target, CompositeWriter writer, MarshalContext ctx) {
86-
writer.setAttribute(ATTRIBUTE_ELEMENTTYPE, ctx.aliasOrNameFor(elementType(target)));
86+
writer.setAttribute(ATTRIBUTE_ELEMENTTYPE, ctx.aliasOrNameFor(elementTypeOf(target)));
8787
}
8888

8989
@Override
@@ -93,9 +93,10 @@ protected void marshalElements(EnumSet target, CompositeWriter writer) {
9393
}
9494
}
9595

96-
private static <E extends Enum<E>> Class<E> elementType(EnumSet<E> source) {
97-
final EnumSet<E> nonEmptySource = source.isEmpty() ? EnumSet.complementOf(source) : source;
98-
return nonEmptySource.iterator().next().getDeclaringClass();
96+
private static <E extends Enum<E>> Class<E> elementTypeOf(EnumSet<E> source) {
97+
return (source.isEmpty() ? EnumSet.complementOf(source) : source).iterator()
98+
.next()
99+
.getDeclaringClass();
99100
}
100101

101102
@Override
@@ -104,19 +105,8 @@ public EnumSet unmarshalNew(CompositeReader reader, UnmarshalContext ctx) throws
104105
}
105106

106107
@Override
107-
public EnumSet unmarshalInit(EnumSet target, CompositeReader reader, UnmarshalContext ctx) {
108-
// consume root element:
109-
reader.next();
110-
// read elements:
111-
final Class elementTypeCls = elementType(target);
112-
while (true) {
113-
if (reader.atElementEnd() && reader.elementName().equals(EnumSetStrategy.NAME)) {
114-
return target;
115-
}
116-
final String elementName = reader.readString();
117-
if (!target.add(Enum.valueOf(elementTypeCls, elementName))) {
118-
throw new InvalidFormatException(ctx.readerPositionDescriptor(), "adding: " + elementName);
119-
}
120-
}
108+
protected Function<CompositeReader, Object> unmarshalElement(EnumSet target, CompositeReader reader, UnmarshalContext ctx) {
109+
final Class elementTypeCls = elementTypeOf(target);
110+
return r -> Enum.valueOf(elementTypeCls, r.readString());
121111
}
122112
}

easyml/src/net/sourceforge/easyml/marshalling/java/util/MapStrategy.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import java.util.Map;
2525
import java.util.Set;
26+
import java.util.function.Function;
2627

2728
/**
2829
* MapStrategy abstract class that implements the {@linkplain CompositeStrategy}
@@ -31,7 +32,7 @@
3132
*
3233
* @param <T> target map class
3334
* @author Victor Cordis ( cordis.victor at gmail.com)
34-
* @version 1.8.1
35+
* @version 1.8.2
3536
* @since 1.0
3637
*/
3738
public abstract class MapStrategy<T extends Map> extends AbstractStrategy implements CompositeStrategy<T> {
@@ -82,19 +83,32 @@ protected void marshalEntrySet(T target, CompositeWriter writer) {
8283
*/
8384
@Override
8485
public T unmarshalInit(T target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
86+
final String endElementName = this.name();
87+
final Function<CompositeReader, Object> unmarshalKey = unmarshalKey(target, reader, ctx);
8588
// consume root element:
8689
reader.next();
8790
// read entries:
88-
final String endElementName = this.name();
8991
while (true) {
9092
if (reader.atElementEnd() && reader.elementName().equals(endElementName)) {
9193
return target;
9294
}
93-
final Object key = reader.read();
95+
final Object key = unmarshalKey.apply(reader);
9496
if (target.containsKey(key)) {
9597
throw new InvalidFormatException(ctx.readerPositionDescriptor(), "duplicate key: " + key);
9698
}
9799
target.put(key, reader.read());
98100
}
99101
}
102+
103+
/**
104+
* Creates a function for reading a key, optionally mapping it.
105+
*
106+
* @param target optionally needed for mapping
107+
* @param reader optionally needed for mapping
108+
* @param ctx optionally needed for mapping
109+
* @return unmarshalling function
110+
*/
111+
protected Function<CompositeReader, Object> unmarshalKey(T target, CompositeReader reader, UnmarshalContext ctx) {
112+
return CompositeReader::read;
113+
}
100114
}

0 commit comments

Comments
 (0)