Skip to content

Commit 13d853d

Browse files
committed
v1.7.1: unmodifiable collections
1 parent a4a6195 commit 13d853d

19 files changed

+760
-130
lines changed

README.md

Lines changed: 7 additions & 2 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.1
64+
- feature: added List.of, Map.of, Set.of strategies.
65+
- feature: added java.util.Collections unmodifiableList, unmodifiableMap, unmodifiableSet strategies.
66+
67+
6368
Release 1.7.0 (requires Java 17, recommended from Java 17)
6469
- feature: support for Java records.
6570

@@ -78,7 +83,7 @@ SingletonList, SingletonSet, SingletonMap strategies.
7883
- feature: added java.util.Collections emptyList, emptyMap, emptySet strategies.
7984

8085

81-
Release 1.5.2 (requires Java 8, recommended up to Java 9)
86+
Release 1.5.2
8287
- feature: added generic mechanism for cache clearing.
8388

8489

@@ -90,7 +95,7 @@ Release 1.5.1
9095
- refactor: remove Profile feature.
9196

9297

93-
Release 1.5.0 (requires Java 8)
98+
Release 1.5.0 (requires Java 8, recommended up to Java 9)
9499
- feature: support for Java 9 security.
95100
- NON-BACKWARD COMPATIBLE refactor of ReflectionUtil.
96101

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

Lines changed: 5 additions & 1 deletion
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.0
87+
* @version 1.7.1
8888
* @see XMLReader
8989
* @see XMLWriter
9090
* @since 1.0
@@ -249,6 +249,7 @@ public static void defaultConfiguration(XMLWriter writer) {
249249
composite.add(ArrayListStrategy.INSTANCE);
250250
composite.add(BitSetStrategy.INSTANCE);
251251
composite.add(CalendarStrategy.INSTANCE);
252+
CollectionsStrategies.forEach(composite::add);
252253
composite.add(EnumMapStrategy.INSTANCE);
253254
composite.add(EnumSetStrategy.INSTANCE);
254255
composite.add(EmptyListStrategy.INSTANCE);
@@ -258,6 +259,7 @@ public static void defaultConfiguration(XMLWriter writer) {
258259
composite.add(HashSetStrategy.INSTANCE);
259260
composite.add(HashtableStrategy.INSTANCE);
260261
composite.add(IdentityHashMapStrategy.INSTANCE);
262+
ImmutableCollectionsStrategies.forEach(composite::add);
261263
composite.add(LinkedHashMapStrategy.INSTANCE);
262264
composite.add(LinkedHashSetStrategy.INSTANCE);
263265
composite.add(LinkedListStrategy.INSTANCE);
@@ -343,6 +345,7 @@ public static void defaultConfiguration(XMLReader reader) {
343345
composite.put(ArrayListStrategy.NAME, ArrayListStrategy.INSTANCE);
344346
composite.put(BitSetStrategy.NAME, BitSetStrategy.INSTANCE);
345347
composite.put(CalendarStrategy.NAME, CalendarStrategy.INSTANCE);
348+
CollectionsStrategies.forEach(s -> composite.put(s.name(), s));
346349
composite.put(EnumMapStrategy.NAME, EnumMapStrategy.INSTANCE);
347350
composite.put(EnumSetStrategy.NAME, EnumSetStrategy.INSTANCE);
348351
composite.put(EmptyListStrategy.NAME, EmptyListStrategy.INSTANCE);
@@ -352,6 +355,7 @@ public static void defaultConfiguration(XMLReader reader) {
352355
composite.put(HashSetStrategy.NAME, HashSetStrategy.INSTANCE);
353356
composite.put(HashtableStrategy.NAME, HashtableStrategy.INSTANCE);
354357
composite.put(IdentityHashMapStrategy.NAME, IdentityHashMapStrategy.INSTANCE);
358+
ImmutableCollectionsStrategies.forEach(s -> composite.put(s.name(), s));
355359
composite.put(LinkedHashMapStrategy.NAME, LinkedHashMapStrategy.INSTANCE);
356360
composite.put(LinkedHashSetStrategy.NAME, LinkedHashSetStrategy.INSTANCE);
357361
composite.put(LinkedListStrategy.NAME, LinkedListStrategy.INSTANCE);

easyml/src/net/sourceforge/easyml/marshalling/CompositeStrategy.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*
2929
* @param <T> target class
3030
* @author Victor Cordis ( cordis.victor at gmail.com)
31-
* @version 1.4.4
31+
* @version 1.7.1
3232
* @since 1.0
3333
*/
3434
public interface CompositeStrategy<T> extends Strategy<T> {
@@ -49,7 +49,8 @@ public interface CompositeStrategy<T> extends Strategy<T> {
4949
/**
5050
* Un-marshaling first step, that is recreate the new instance,possibly
5151
* using the <code>reader</code> to read XML attributes which can
52-
* parameterize the instantiation. <br/> <b>Note:</b> the reader's position
52+
* parameterize the instantiation.<br/>
53+
* <b>Note:</b> the reader's position
5354
* is at the composite root element start and must not be moved after the
5455
* root element end.
5556
*
@@ -66,18 +67,22 @@ T unmarshalNew(CompositeReader reader, UnmarshalContext ctx)
6667
/**
6768
* Un-marshaling second step, that is initialize the instance created at
6869
* step one, possibly using the <code>reader</code> to read XML elements.
69-
* <br/> <b>Note:</b> the reader's position is where it was left at the
70-
* first step and must be left at the root element end. <br/> <b>Note:</b>
71-
* for recursive un-marshalling one must use the {@linkplain CompositeReader#read()
72-
* } method because of internal computations such as graph-traversal
73-
* marking.
70+
* This defaults to a non-op, useful for immutable types which are
71+
* fully processed at {@linkplain #unmarshalNew(CompositeReader, UnmarshalContext)}.
72+
* <br/>
73+
* <b>Note:</b> the reader's position is where it was left at the
74+
* first step and must be left at the root element end.
75+
* <br/>
76+
* <b>Note:</b> for recursive un-marshalling one must use the {@linkplain CompositeReader#read()}
77+
* method because of internal computations such as graph-traversal marking.
7478
*
7579
* @param target to initialize
7680
* @param reader reads XML elements
7781
* @param ctx the un-marshalling context
78-
* @return the initialized instance, possibly not the one referred by
79-
* <code>target</code>
82+
* @return the initialized instance, possibly not the one referred by <code>target</code>
8083
* @throws IllegalAccessException if a class initialization fails
8184
*/
82-
Object unmarshalInit(T target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException;
85+
default Object unmarshalInit(T target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
86+
return target;
87+
}
8388
}

easyml/src/net/sourceforge/easyml/marshalling/java/awt/ColorStrategy.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
* thread-safe.
3030
*
3131
* @author Victor Cordis ( cordis.victor at gmail.com)
32-
* @version 1.2.4
32+
* @version 1.7.1
3333
* @since 1.0
3434
*/
3535
public final class ColorStrategy extends AbstractStrategy implements CompositeStrategy<Color> {
@@ -109,15 +109,8 @@ public Color unmarshalNew(CompositeReader reader, UnmarshalContext ctx) {
109109
Integer.parseInt(reader.elementRequiredAttribute(ATTRIBUTE_BLUE)));
110110
} catch (NumberFormatException nfx) {
111111
throw new InvalidFormatException(ctx.readerPositionDescriptor(), nfx);
112+
} finally {
113+
reader.next(); // moved the reader from the root element start to end.
112114
}
113115
}
114-
115-
/**
116-
* {@inheritDoc }
117-
*/
118-
@Override
119-
public Color unmarshalInit(Color target, CompositeReader reader, UnmarshalContext ctx) {
120-
reader.next(); // moved the reader from the root element start to end.
121-
return target;
122-
}
123116
}

easyml/src/net/sourceforge/easyml/marshalling/java/lang/RecordStrategy.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* This implementation is thread-safe.
3535
*
3636
* @author Victor Cordis ( cordis.victor at gmail.com)
37-
* @version 1.7.0
37+
* @version 1.7.1
3838
* @since 1.7.0
3939
*/
4040
public final class RecordStrategy extends AbstractStrategy implements CompositeStrategy<Record> {
@@ -157,12 +157,4 @@ private static Record newRecord(Class recordClass, RecordComponent[] recordCompo
157157
.asType(MethodType.methodType(Object.class, paramTypes));
158158
return (Record) constructorMH.invokeWithArguments(args);
159159
}
160-
161-
/**
162-
* {@inheritDoc }
163-
*/
164-
@Override
165-
public Record unmarshalInit(Record target, CompositeReader reader, UnmarshalContext ctx) {
166-
return target;
167-
}
168160
}

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* This implementation is thread-safe.
3131
*
3232
* @author Victor Cordis ( cordis.victor at gmail.com)
33-
* @version 1.5.1
33+
* @version 1.7.1
3434
* @since 1.5.1
3535
*/
3636
public final class CalendarStrategy extends AbstractStrategy implements CompositeStrategy<Calendar> {
@@ -108,12 +108,4 @@ public Calendar unmarshalNew(CompositeReader reader, UnmarshalContext ctx) {
108108
throw new InvalidFormatException(ctx.readerPositionDescriptor(), nfx);
109109
}
110110
}
111-
112-
/**
113-
* {@inheritDoc }
114-
*/
115-
@Override
116-
public Object unmarshalInit(Calendar target, CompositeReader reader, UnmarshalContext ctx) {
117-
return target;
118-
}
119111
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Copyright 2012 Victor Cordis
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* Please contact the author ( [email protected] ) if you need additional
17+
* information or have any questions.
18+
*/
19+
package net.sourceforge.easyml.marshalling.java.util;
20+
21+
import net.sourceforge.easyml.InvalidFormatException;
22+
import net.sourceforge.easyml.marshalling.CompositeReader;
23+
import net.sourceforge.easyml.marshalling.CompositeStrategy;
24+
import net.sourceforge.easyml.marshalling.CompositeWriter;
25+
import net.sourceforge.easyml.marshalling.UnmarshalContext;
26+
27+
import java.util.*;
28+
import java.util.function.Consumer;
29+
30+
/**
31+
* CollectionsStrategies class contains strategies for {@linkplain List#of()}, {@linkplain Map#of()},
32+
* {@linkplain Set#of()} factory methods.
33+
* Implementations are thread-safe.
34+
*
35+
* @author Victor Cordis ( cordis.victor at gmail.com)
36+
* @version 1.7.1
37+
* @since 1.7.1
38+
*/
39+
public final class CollectionsStrategies {
40+
41+
/**
42+
* Constant defining the value used for the unmodifiable list strategy name.
43+
*/
44+
public static final String NAME_UNMODIFIABLE_LIST = "unmodif-lst";
45+
/**
46+
* Constant defining the singleton unmodifiable list instance.
47+
*/
48+
public static final CompositeStrategy<List> INSTANCE_UNMODIFIABLE_LIST = new CollectionStrategy<>() {
49+
50+
private static final Class TARGET = Collections.unmodifiableList(new LinkedList<>()).getClass();
51+
52+
@Override
53+
public Class target() {
54+
return TARGET;
55+
}
56+
57+
@Override
58+
public String name() {
59+
return NAME_UNMODIFIABLE_LIST;
60+
}
61+
62+
@Override
63+
protected void marshalAttr(List target, CompositeWriter writer) {
64+
}
65+
66+
@Override
67+
public List unmarshalNew(CompositeReader reader, UnmarshalContext ctx) {
68+
return new LinkedList();
69+
}
70+
71+
@Override
72+
public List unmarshalInit(List target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
73+
super.unmarshalInit(target, reader, ctx);
74+
return Collections.unmodifiableList(target);
75+
}
76+
};
77+
78+
/**
79+
* Constant defining the value used for the unmodifiable random access list strategy name.
80+
*/
81+
public static final String NAME_UNMODIFIABLE_LIST_RA = "unmodif-lst-ra";
82+
/**
83+
* Constant defining the singleton unmodifiable random access list instance.
84+
*/
85+
public static final CompositeStrategy<List> INSTANCE_UNMODIFIABLE_LIST_RA = new CollectionStrategy<>() {
86+
87+
private static final Class TARGET = Collections.unmodifiableList(Collections.EMPTY_LIST).getClass();
88+
89+
@Override
90+
public Class target() {
91+
return TARGET;
92+
}
93+
94+
@Override
95+
public String name() {
96+
return NAME_UNMODIFIABLE_LIST_RA;
97+
}
98+
99+
100+
@Override
101+
public List unmarshalNew(CompositeReader reader, UnmarshalContext ctx) {
102+
try {
103+
return new ArrayList(Integer.parseInt(reader.elementRequiredAttribute(ATTRIBUTE_SIZE)));
104+
} catch (NumberFormatException nfx) {
105+
throw new InvalidFormatException(ctx.readerPositionDescriptor(), nfx);
106+
}
107+
}
108+
109+
@Override
110+
public List unmarshalInit(List target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
111+
super.unmarshalInit(target, reader, ctx);
112+
return Collections.unmodifiableList(target);
113+
}
114+
};
115+
116+
/**
117+
* Constant defining the value used for the unmodifiable map strategy name.
118+
*/
119+
public static final String NAME_UNMODIFIABLE_MAP = "unmodif-map";
120+
/**
121+
* Constant defining the singleton unmodifiable map instance.
122+
*/
123+
public static final CompositeStrategy<Map> INSTANCE_UNMODIFIABLE_MAP = new MapStrategy<>() {
124+
125+
private static final Class TARGET = Collections.unmodifiableMap(Collections.EMPTY_MAP).getClass();
126+
127+
@Override
128+
public Class target() {
129+
return TARGET;
130+
}
131+
132+
@Override
133+
public String name() {
134+
return NAME_UNMODIFIABLE_MAP;
135+
}
136+
137+
@Override
138+
public Map unmarshalNew(CompositeReader reader, UnmarshalContext ctx) {
139+
try {
140+
return new HashMap(Integer.parseInt(reader.elementRequiredAttribute(ATTRIBUTE_SIZE)));
141+
} catch (NumberFormatException nfx) {
142+
throw new InvalidFormatException(ctx.readerPositionDescriptor(), nfx);
143+
}
144+
}
145+
146+
@Override
147+
public Map unmarshalInit(Map target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
148+
super.unmarshalInit(target, reader, ctx);
149+
return Collections.unmodifiableMap(target);
150+
}
151+
};
152+
153+
/**
154+
* Constant defining the value used for the unmodifiable set strategy name.
155+
*/
156+
public static final String NAME_UNMODIFIABLE_SET = "unmodif-set";
157+
/**
158+
* Constant defining the singleton unmodifiable set instance.
159+
*/
160+
public static final CompositeStrategy<Set> INSTANCE_UNMODIFIABLE_SET = new CollectionStrategy<>() {
161+
162+
private static final Class TARGET = Collections.unmodifiableSet(Collections.EMPTY_SET).getClass();
163+
164+
@Override
165+
public Class target() {
166+
return TARGET;
167+
}
168+
169+
@Override
170+
public String name() {
171+
return NAME_UNMODIFIABLE_SET;
172+
}
173+
174+
@Override
175+
public Set unmarshalNew(CompositeReader reader, UnmarshalContext ctx) {
176+
try {
177+
return new HashSet(Integer.parseInt(reader.elementRequiredAttribute(ATTRIBUTE_SIZE)));
178+
} catch (NumberFormatException nfx) {
179+
throw new InvalidFormatException(ctx.readerPositionDescriptor(), nfx);
180+
}
181+
}
182+
183+
@Override
184+
public Set unmarshalInit(Set target, CompositeReader reader, UnmarshalContext ctx) throws IllegalAccessException {
185+
super.unmarshalInit(target, reader, ctx);
186+
return Collections.unmodifiableSet(target);
187+
}
188+
};
189+
190+
/**
191+
* Consumes each strategy.
192+
*
193+
* @param c consumer
194+
*/
195+
public static void forEach(Consumer<CompositeStrategy> c) {
196+
c.accept(INSTANCE_UNMODIFIABLE_LIST);
197+
c.accept(INSTANCE_UNMODIFIABLE_MAP);
198+
c.accept(INSTANCE_UNMODIFIABLE_SET);
199+
}
200+
201+
private CollectionsStrategies() {
202+
}
203+
}

0 commit comments

Comments
 (0)