Skip to content

Commit 809c354

Browse files
committed
v1.7.2: writer reader EasyML APIs and HexFormat
1 parent 13d853d commit 809c354

File tree

8 files changed

+266
-85
lines changed

8 files changed

+266
-85
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.7.2
64+
- refactor: improved XML writer, reader and EasyML APIs
65+
- feature: added HexFormat strategy.
66+
67+
6368
Release 1.7.1
6469
- feature: added List.of, Map.of, Set.of strategies.
6570
- feature: added java.util.Collections unmodifiableList, unmodifiableMap, unmodifiableSet strategies.

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

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
* objects.<br/>
8585
*
8686
* @author Victor Cordis ( cordis.victor at gmail.com)
87-
* @version 1.7.1
87+
* @version 1.7.2
8888
* @see XMLReader
8989
* @see XMLWriter
9090
* @since 1.0
@@ -183,7 +183,7 @@ public void applyTo(XMLWriter writer) {
183183
*/
184184
public EasyML() {
185185
this.writerPrototype = new XMLWriter();
186-
this.readerPrototype = new XMLReader(new ConcurrentHashMap<>());
186+
this.readerPrototype = new XMLReader(ConcurrentHashMap::new);
187187
defaultConfiguration(this.writerPrototype);
188188
defaultConfiguration(this.readerPrototype);
189189
this.perThreadWriter = ThreadLocal.withInitial(() -> new XMLWriter(writerPrototype));
@@ -258,6 +258,7 @@ public static void defaultConfiguration(XMLWriter writer) {
258258
composite.add(HashMapStrategy.INSTANCE);
259259
composite.add(HashSetStrategy.INSTANCE);
260260
composite.add(HashtableStrategy.INSTANCE);
261+
composite.add(HexFormatStrategy.INSTANCE);
261262
composite.add(IdentityHashMapStrategy.INSTANCE);
262263
ImmutableCollectionsStrategies.forEach(composite::add);
263264
composite.add(LinkedHashMapStrategy.INSTANCE);
@@ -354,6 +355,7 @@ public static void defaultConfiguration(XMLReader reader) {
354355
composite.put(HashMapStrategy.NAME, HashMapStrategy.INSTANCE);
355356
composite.put(HashSetStrategy.NAME, HashSetStrategy.INSTANCE);
356357
composite.put(HashtableStrategy.NAME, HashtableStrategy.INSTANCE);
358+
composite.put(HexFormatStrategy.NAME, HexFormatStrategy.INSTANCE);
357359
composite.put(IdentityHashMapStrategy.NAME, IdentityHashMapStrategy.INSTANCE);
358360
ImmutableCollectionsStrategies.forEach(s -> composite.put(s.name(), s));
359361
composite.put(LinkedHashMapStrategy.NAME, LinkedHashMapStrategy.INSTANCE);
@@ -382,6 +384,9 @@ public static void defaultConfiguration(XMLReader reader) {
382384
composite.put(PatternStrategy.NAME, PatternStrategy.INSTANCE);
383385
}
384386

387+
/**
388+
* To be used by {@linkplain EasyMLBuilder} only.
389+
*/
385390
EasyML(Style style, Supplier<XmlPullParser> xmlPullParserProvider,
386391
String dateFormat, String customRootTag, Map<Class, String> classToAlias, Map<Field, String> fieldToAlias,
387392
Set<Field> excludedFields, XMLReader.SecurityPolicy deserializationSecurityPolicy,
@@ -574,7 +579,7 @@ public XMLWriter newWriter(Document out) {
574579
*/
575580
public XMLReader newReader(Reader in) {
576581
final XMLReader ret = new XMLReader(readerPrototype);
577-
ret.reset(in, maybeProvidedXmlPullParser());
582+
ret.reset(in, maybeXmlPullParserProvider());
578583
return ret;
579584
}
580585

@@ -590,7 +595,9 @@ public XMLReader newReader(Reader in) {
590595
* @return a new shared-configuration reader
591596
*/
592597
public XMLReader newReader(InputStream in) {
593-
return this.newReader(new InputStreamReader(in));
598+
final XMLReader ret = new XMLReader(readerPrototype);
599+
ret.reset(in, maybeXmlPullParserProvider());
600+
return ret;
594601
}
595602

596603
/**
@@ -625,8 +632,11 @@ public XMLReader newReader(Document in) {
625632
public void serialize(Object o, Writer out) {
626633
final XMLWriter writer = this.perThreadWriter.get();
627634
writer.reset(out);
628-
writer.write(o);
629-
writer.flush();
635+
try {
636+
writer.write(o);
637+
} finally {
638+
writer.flush();
639+
}
630640
}
631641

632642
/**
@@ -668,8 +678,11 @@ public String serialize(Object o) {
668678
public void serialize(Object o, Document out) {
669679
final XMLWriter writer = this.perThreadWriter.get();
670680
writer.reset(out);
671-
writer.write(o);
672-
writer.flush();
681+
try {
682+
writer.write(o);
683+
} finally {
684+
writer.flush();
685+
}
673686
}
674687

675688
/**
@@ -682,11 +695,11 @@ public void serialize(Object o, Document out) {
682695
*/
683696
public Object deserialize(Reader in) {
684697
final XMLReader reader = this.perThreadReader.get();
685-
reader.reset(in, maybeProvidedXmlPullParser());
698+
reader.reset(in, maybeXmlPullParserProvider());
686699
return reader.read();
687700
}
688701

689-
private XmlPullParser maybeProvidedXmlPullParser() {
702+
private XmlPullParser maybeXmlPullParserProvider() {
690703
return this.xmlPullParserProvider != null ? this.xmlPullParserProvider.get() : null;
691704
}
692705

@@ -733,7 +746,7 @@ public Object deserialize(Document in) {
733746
/**
734747
* Releases the XML writer, if any, belonging to the current thread. If this
735748
* method isn't invoked, the XML writer will be released anyway at the
736-
* current threads death.
749+
* current thread's death.
737750
* <br>
738751
* <b>Note:</b> this is an advanced feature and should be used only if the
739752
* caller knows this thread won't be using this EasyML instance for
@@ -746,7 +759,7 @@ public void releaseCurrentWriter() {
746759
/**
747760
* Releases the XML reader, if any, belonging to the current thread. If this
748761
* method isn't invoked, the XML reader will be released anyway at the
749-
* current threads death.
762+
* current thread's death.
750763
* <br>
751764
* <b>Note:</b> this is an advanced feature and should be used only if the
752765
* caller knows this thread won't be using this EasyML instance for

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

Lines changed: 68 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
* shared configuration can be created, via constructors.
6666
*
6767
* @author Victor Cordis ( cordis.victor at gmail.com)
68-
* @version 1.6.0
68+
* @version 1.7.2
6969
* @see XMLWriter
7070
* @since 1.0
7171
*/
@@ -353,8 +353,8 @@ public final Object read() {
353353
/**
354354
* Reads from the current position, recursively.
355355
*
356-
* @param componentType array componentType, if the expected result is
357-
* an array with no class attribute, null otherwise
356+
* @param componentType array componentType, if the expected result is an array with no class attribute,
357+
* null otherwise
358358
* @return the read object
359359
*/
360360
@Override
@@ -391,6 +391,14 @@ public S put(String key, S value) {
391391
}
392392
}
393393

394+
@FunctionalInterface
395+
interface AliasingReflectionCacheSupplier {
396+
397+
AliasingReflectionCacheSupplier DEFAULT = HashMap::new;
398+
399+
Map<String, Object> get();
400+
}
401+
394402
private static final char FIELD_FQN_SEPARATOR = '#';
395403
private Driver driver;
396404
private boolean beforeRoot;
@@ -405,21 +413,47 @@ public S put(String key, S value) {
405413
/* default*/ SecurityPolicy securityPolicy;
406414

407415
/**
408-
* Creates a new configuration prototype instance, to be used by
409-
* {@linkplain EasyML} only.
416+
* Creates a new configuration prototype instance.
417+
* To be used by {@linkplain EasyML} only.
410418
*/
411-
XMLReader(Map<String, Object> aliasFieldCache) {
419+
XMLReader(AliasingReflectionCacheSupplier getAliasingReflectionCache) {
412420
this.driver = null;
413-
this.init(aliasFieldCache);
421+
this.init(getAliasingReflectionCache);
422+
}
423+
424+
private void init(AliasingReflectionCacheSupplier getAliasingReflectionCache) {
425+
this.beforeRoot = true;
426+
this.rootTag = DTD.ELEMENT_EASYML;
427+
this.decoded = new HashMap<>();
428+
this.sharedConfiguration = false;
429+
this.context = new UnmarshalContextImpl();
430+
this.cachedAliasingReflection = getAliasingReflectionCache.get();
431+
this.simpleStrategies = new StrategyHashMap<>();
432+
this.compositeStrategies = new StrategyHashMap<>();
433+
this.dateFormat = new SimpleDateFormat(DTD.FORMAT_DATE);
434+
this.securityPolicy = null; // lazy.
435+
// add DTD strategies by default:
436+
this.simpleStrategies.put(DTD.TYPE_BASE64, Base64Strategy.INSTANCE);
437+
this.simpleStrategies.put(DTD.TYPE_BOOLEAN, BooleanStrategy.INSTANCE);
438+
this.simpleStrategies.put(DTD.TYPE_DATE, DateStrategy.INSTANCE);
439+
this.simpleStrategies.put(DTD.TYPE_DOUBLE, DoubleStrategy.INSTANCE);
440+
this.simpleStrategies.put(DTD.TYPE_INT, IntStrategy.INSTANCE);
441+
this.simpleStrategies.put(DTD.TYPE_STRING, StringStrategy.INSTANCE);
442+
// add NON-DTD strategies for primitives, since we need to support the primitive API:
443+
this.simpleStrategies.put(ByteStrategy.NAME, ByteStrategy.INSTANCE);
444+
this.simpleStrategies.put(CharacterStrategy.NAME, CharacterStrategy.INSTANCE);
445+
this.simpleStrategies.put(FloatStrategy.NAME, FloatStrategy.INSTANCE);
446+
this.simpleStrategies.put(LongStrategy.NAME, LongStrategy.INSTANCE);
447+
this.simpleStrategies.put(ShortStrategy.NAME, ShortStrategy.INSTANCE);
414448
}
415449

416450
/**
417-
* Creates a new shared-configuration instance, to be used by
418-
* {@linkplain EasyML} only.
451+
* Creates a new shared-configuration instance.
452+
* To be used by {@linkplain EasyML} only.
419453
*/
420-
XMLReader(XMLReader configured) {
454+
XMLReader(XMLReader prototype) {
421455
this.driver = null;
422-
this.initIdentically(configured);
456+
this.initIdentically(prototype);
423457
}
424458

425459
private void initIdentically(XMLReader other) {
@@ -444,37 +478,7 @@ private void initIdentically(XMLReader other) {
444478
*/
445479
public XMLReader(Reader reader) {
446480
this.driver = new XMLReaderTextDriver(this, reader);
447-
this.init();
448-
}
449-
450-
private void init() {
451-
this.init(new HashMap<>());
452-
}
453-
454-
private void init(Map<String, Object> aliasReflectCache) {
455-
this.beforeRoot = true;
456-
this.rootTag = DTD.ELEMENT_EASYML;
457-
this.decoded = new HashMap<>();
458-
this.sharedConfiguration = false;
459-
this.context = new UnmarshalContextImpl();
460-
this.cachedAliasingReflection = aliasReflectCache;
461-
this.simpleStrategies = new StrategyHashMap<>();
462-
this.compositeStrategies = new StrategyHashMap<>();
463-
this.dateFormat = new SimpleDateFormat(DTD.FORMAT_DATE);
464-
this.securityPolicy = null; // lazy.
465-
// add DTD strategies by default:
466-
this.simpleStrategies.put(DTD.TYPE_BASE64, Base64Strategy.INSTANCE);
467-
this.simpleStrategies.put(DTD.TYPE_BOOLEAN, BooleanStrategy.INSTANCE);
468-
this.simpleStrategies.put(DTD.TYPE_DATE, DateStrategy.INSTANCE);
469-
this.simpleStrategies.put(DTD.TYPE_DOUBLE, DoubleStrategy.INSTANCE);
470-
this.simpleStrategies.put(DTD.TYPE_INT, IntStrategy.INSTANCE);
471-
this.simpleStrategies.put(DTD.TYPE_STRING, StringStrategy.INSTANCE);
472-
// add NON-DTD strategies for primitives, since we need to support the primitive API:
473-
this.simpleStrategies.put(ByteStrategy.NAME, ByteStrategy.INSTANCE);
474-
this.simpleStrategies.put(CharacterStrategy.NAME, CharacterStrategy.INSTANCE);
475-
this.simpleStrategies.put(FloatStrategy.NAME, FloatStrategy.INSTANCE);
476-
this.simpleStrategies.put(LongStrategy.NAME, LongStrategy.INSTANCE);
477-
this.simpleStrategies.put(ShortStrategy.NAME, ShortStrategy.INSTANCE);
481+
this.init(AliasingReflectionCacheSupplier.DEFAULT);
478482
}
479483

480484
/**
@@ -485,8 +489,7 @@ private void init(Map<String, Object> aliasReflectCache) {
485489
* @param in stream from which to read
486490
*/
487491
public XMLReader(InputStream in) {
488-
this.driver = new XMLReaderTextDriver(this, new InputStreamReader(in));
489-
this.init();
492+
this(new InputStreamReader(in));
490493
}
491494

492495
/**
@@ -499,7 +502,7 @@ public XMLReader(InputStream in) {
499502
*/
500503
public XMLReader(Reader reader, XmlPullParser parser) {
501504
this.driver = new XMLReaderTextDriver(this, reader, parser);
502-
this.init();
505+
this.init(AliasingReflectionCacheSupplier.DEFAULT);
503506
}
504507

505508
/**
@@ -511,8 +514,7 @@ public XMLReader(Reader reader, XmlPullParser parser) {
511514
* @param parser to process the in XML with
512515
*/
513516
public XMLReader(InputStream in, XmlPullParser parser) {
514-
this.driver = new XMLReaderTextDriver(this, new InputStreamReader(in), parser);
515-
this.init();
517+
this(new InputStreamReader(in), parser);
516518
}
517519

518520
/**
@@ -523,7 +525,21 @@ public XMLReader(InputStream in, XmlPullParser parser) {
523525
*/
524526
public XMLReader(Document in) {
525527
this.driver = new XMLReaderDOMDriver(this, in);
526-
this.init();
528+
this.init(AliasingReflectionCacheSupplier.DEFAULT);
529+
}
530+
531+
/**
532+
* Creates a new instance with the given <code>driver</code>.
533+
* For generic formats, other than XML.
534+
*
535+
* @param driver for generic formats
536+
*/
537+
public XMLReader(XMLReader.Driver driver) {
538+
if (driver == null) {
539+
throw new IllegalArgumentException("driver: null");
540+
}
541+
this.driver = driver;
542+
this.init(AliasingReflectionCacheSupplier.DEFAULT);
527543
}
528544

529545
/**
@@ -1045,20 +1061,17 @@ private boolean isRootEnd() {
10451061
* @param parser to use, null if default
10461062
*/
10471063
public void reset(Reader reader, XmlPullParser parser) {
1048-
if (isReusableXMLReaderTextDriver()) {
1064+
if (this.driver != null && this.driver.getClass() == XMLReaderTextDriver.class) {
10491065
((XMLReaderTextDriver) this.driver).reset(reader, parser);
10501066
} else {
1051-
this.driver = parser != null ? new XMLReaderTextDriver(this, reader, parser)
1052-
: new XMLReaderTextDriver(this, reader);
1067+
this.driver = parser != null ?
1068+
new XMLReaderTextDriver(this, reader, parser) :
1069+
new XMLReaderTextDriver(this, reader);
10531070
}
10541071
this.decoded.clear();
10551072
this.beforeRoot = true;
10561073
}
10571074

1058-
private boolean isReusableXMLReaderTextDriver() {
1059-
return this.driver != null && this.driver.getClass() == XMLReaderTextDriver.class;
1060-
}
1061-
10621075
/**
10631076
* Resets this instance, setting it to the new <code>in</code> stream.
10641077
*

easyml/src/net/sourceforge/easyml/XMLReaderTextDriver.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,7 @@ protected void consumeFully() {
194194
* recreate and should be reused.
195195
*
196196
* @param in the required input reader
197-
* @param parser optional custom parser to replace the default pull-parse
198-
* implementation
197+
* @param parser optional custom parser to replace the default pull-parse implementation
199198
*/
200199
public void reset(Reader in, XmlPullParser parser) {
201200
if (parser != null) {

0 commit comments

Comments
 (0)