Skip to content

Commit cc44f07

Browse files
committed
Ability to set custom collection type
1 parent 6d71f7a commit cc44f07

File tree

4 files changed

+103
-33
lines changed

4 files changed

+103
-33
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (C) 2023 Elytrium
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package net.elytrium.serializer.annotations;
19+
20+
import java.lang.annotation.Documented;
21+
import java.lang.annotation.ElementType;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
import java.util.Collection;
26+
27+
/**
28+
* Changes collection type
29+
*/
30+
@SuppressWarnings("rawtypes")
31+
@Documented
32+
@Retention(RetentionPolicy.RUNTIME)
33+
@Target({ElementType.FIELD})
34+
public @interface CollectionType {
35+
36+
/**
37+
* @return Class that will be initialized when the Collection field is read. (e.g. ArrayList.class)
38+
*/
39+
Class<? extends Collection> value();
40+
}

src/main/java/net/elytrium/serializer/language/reader/AbstractReader.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121
import java.io.IOException;
2222
import java.lang.reflect.Constructor;
2323
import java.lang.reflect.Field;
24+
import java.lang.reflect.InvocationTargetException;
2425
import java.lang.reflect.ParameterizedType;
2526
import java.lang.reflect.Type;
2627
import java.util.ArrayDeque;
28+
import java.util.ArrayList;
2729
import java.util.Collection;
2830
import java.util.Deque;
31+
import java.util.HashSet;
2932
import java.util.List;
3033
import java.util.Map;
3134
import java.util.Queue;
@@ -34,6 +37,7 @@
3437
import java.util.logging.Logger;
3538
import javax.annotation.Nullable;
3639
import net.elytrium.serializer.SerializerConfig;
40+
import net.elytrium.serializer.annotations.CollectionType;
3741
import net.elytrium.serializer.annotations.Serializer;
3842
import net.elytrium.serializer.custom.ClassSerializer;
3943
import net.elytrium.serializer.exceptions.ReflectionException;
@@ -203,13 +207,37 @@ public Object readByType(@Nullable Field owner, @Nullable Object holder, Type ty
203207
GenericUtils.getParameterType(Map.class, parameterizedType, 0),
204208
GenericUtils.getParameterType(Map.class, parameterizedType, 1));
205209
} else if (Collection.class.isAssignableFrom(clazz)) {
206-
Type collectionType = GenericUtils.getParameterType(Collection.class, parameterizedType, 0);
210+
Type collectionEntryType = GenericUtils.getParameterType(Collection.class, parameterizedType, 0);
211+
if (owner != null) {
212+
CollectionType collectionType = owner.getAnnotation(CollectionType.class);
213+
if (collectionType != null) {
214+
try {
215+
//noinspection unchecked
216+
return this.readCollection(owner,
217+
(Collection<Object>) collectionType.value().getDeclaredConstructor().newInstance(),
218+
collectionEntryType);
219+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
220+
throw new SerializableReadException(e);
221+
}
222+
} else {
223+
try {
224+
//noinspection unchecked
225+
return this.readCollection(owner,
226+
(Collection<Object>) owner.getType().getDeclaredConstructor().newInstance(),
227+
collectionEntryType);
228+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
229+
throw new SerializableReadException(e);
230+
} catch (NoSuchMethodException e) {
231+
// Ignoring NoSuchMethod.
232+
}
233+
}
234+
}
207235
if (Set.class.isAssignableFrom(clazz)) {
208-
return this.readSet(collectionType);
236+
return this.readSet(collectionEntryType);
209237
} else if (Queue.class.isAssignableFrom(clazz)) {
210-
return this.readDeque(collectionType);
238+
return this.readDeque(collectionEntryType);
211239
} else {
212-
return this.readList(collectionType);
240+
return this.readList(collectionEntryType);
213241
}
214242
} else {
215243
return this.readGuessingType(owner);
@@ -274,6 +302,16 @@ public Map<Object, Object> readMap(Type keyType, Type valueType) {
274302

275303
public abstract Map<Object, Object> readMap(@Nullable Field owner, Type keyType, Type valueType);
276304

305+
public <C extends Collection<Object>> C readCollection(@Nullable Field owner, C result) {
306+
return this.readCollection(owner, result, Object.class);
307+
}
308+
309+
public <C extends Collection<Object>> C readCollection(C result, Type type) {
310+
return this.readCollection(null, result, type);
311+
}
312+
313+
public abstract <C extends Collection<Object>> C readCollection(@Nullable Field owner, C result, Type type);
314+
277315
public List<Object> readList(@Nullable Field owner) {
278316
return this.readList(owner, Object.class);
279317
}
@@ -282,7 +320,9 @@ public List<Object> readList(Type type) {
282320
return this.readList(null, type);
283321
}
284322

285-
public abstract List<Object> readList(@Nullable Field owner, Type type);
323+
public List<Object> readList(@Nullable Field owner, Type type) {
324+
return this.readCollection(owner, new ArrayList<>(), type);
325+
}
286326

287327
public Set<Object> readSet(@Nullable Field owner) {
288328
return this.readSet(owner, Object.class);
@@ -292,7 +332,9 @@ public Set<Object> readSet(Type type) {
292332
return this.readSet(null, type);
293333
}
294334

295-
public abstract Set<Object> readSet(@Nullable Field owner, Type type);
335+
public Set<Object> readSet(@Nullable Field owner, Type type) {
336+
return this.readCollection(owner, new HashSet<>(), type);
337+
}
296338

297339
public Deque<Object> readDeque(@Nullable Field owner) {
298340
return this.readDeque(owner, Object.class);
@@ -302,7 +344,9 @@ public Deque<Object> readDeque(Type type) {
302344
return this.readDeque(null, type);
303345
}
304346

305-
public abstract Deque<Object> readDeque(@Nullable Field owner, Type type);
347+
public Deque<Object> readDeque(@Nullable Field owner, Type type) {
348+
return this.readCollection(owner, new ArrayDeque<>(), type);
349+
}
306350

307351
public String readString() {
308352
return this.readString(null);

src/main/java/net/elytrium/serializer/language/reader/YamlReader.java

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,9 @@
2828
import java.util.Collection;
2929
import java.util.Deque;
3030
import java.util.HashMap;
31-
import java.util.HashSet;
3231
import java.util.LinkedHashMap;
3332
import java.util.List;
3433
import java.util.Map;
35-
import java.util.Set;
3634
import java.util.logging.Level;
3735
import java.util.logging.Logger;
3836
import net.elytrium.serializer.SerializerConfig;
@@ -265,23 +263,9 @@ public Map<Object, Object> readMap(@Nullable Field owner, Type keyType, Type val
265263
}
266264

267265
@Override
268-
public List<Object> readList(@Nullable Field owner, Type type) {
266+
public <C extends Collection<Object>> C readCollection(@Nullable Field owner, C result, Type type) {
269267
synchronized (this) {
270-
return this.readListByMarker(owner, type, this.readRawIgnoreEmpty());
271-
}
272-
}
273-
274-
@Override
275-
public Set<Object> readSet(@Nullable Field owner, Type type) {
276-
synchronized (this) {
277-
return this.readListByMarker(new HashSet<>(), owner, type, this.readRawIgnoreEmpty());
278-
}
279-
}
280-
281-
@Override
282-
public Deque<Object> readDeque(@Nullable Field owner, Type type) {
283-
synchronized (this) {
284-
return this.readListByMarker(new ArrayDeque<>(), owner, type, this.readRawIgnoreEmpty());
268+
return this.readCollectionByMarker(owner, result, type, this.readRawIgnoreEmpty());
285269
}
286270
}
287271

@@ -413,12 +397,12 @@ public Long readLong(@Nullable Field owner) throws NumberFormatException {
413397
}
414398
}
415399

416-
private List<Object> readListByMarker(@Nullable Field owner, Type type, char marker) {
417-
return this.readListByMarker(new ArrayList<>(), owner, type, marker);
400+
private List<Object> readListByMarker(@Nullable Field owner, char marker) {
401+
return this.readCollectionByMarker(owner, new ArrayList<>(), Object.class, marker);
418402
}
419403

420404
@SuppressFBWarnings("SA_FIELD_SELF_COMPARISON")
421-
private <C extends Collection<Object>> C readListByMarker(C result, @Nullable Field owner, Type type, char marker) {
405+
private <C extends Collection<Object>> C readCollectionByMarker(@Nullable Field owner, C result, Type type, char marker) {
422406
if (this.skipComments(owner, marker, false)) {
423407
marker = AbstractReader.NEW_LINE;
424408
}
@@ -606,7 +590,7 @@ private Object readGuessingTypeByMarker(@Nullable Field owner, char marker) {
606590
case AbstractReader.NEW_LINE -> {
607591
char nextMarker = this.readRawIgnoreEmpty();
608592
this.setReuseBuffer();
609-
yield nextMarker == '-' ? this.readListByMarker(owner, Object.class, marker) : this.readMapByMarker(owner, Object.class, Object.class, marker);
593+
yield nextMarker == '-' ? this.readListByMarker(owner, marker) : this.readMapByMarker(owner, Object.class, Object.class, marker);
610594
}
611595
case '-' -> {
612596
this.setReuseBuffer();
@@ -625,9 +609,9 @@ private Object readGuessingTypeByMarker(@Nullable Field owner, char marker) {
625609
}
626610

627611
this.unsetSeek();
628-
yield this.readListByMarker(owner, Object.class, AbstractReader.NEW_LINE);
612+
yield this.readListByMarker(owner, AbstractReader.NEW_LINE);
629613
}
630-
case '[' -> this.readListByMarker(owner, Object.class, marker);
614+
case '[' -> this.readListByMarker(owner, marker);
631615
case '{' -> this.readMapByMarker(owner, Object.class, Object.class, marker);
632616
case '"', '\'', '>', '|' -> this.readStringFromMarker(owner, marker, false);
633617
default -> {

src/test/java/net/elytrium/serializer/SerializerTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
import java.nio.file.Paths;
3030
import java.util.ArrayDeque;
3131
import java.util.Arrays;
32+
import java.util.Collection;
3233
import java.util.Date;
3334
import java.util.Deque;
3435
import java.util.HashSet;
3536
import java.util.LinkedHashMap;
3637
import java.util.List;
3738
import java.util.Map;
38-
import java.util.Set;
39+
import net.elytrium.serializer.annotations.CollectionType;
3940
import net.elytrium.serializer.annotations.Comment;
4041
import net.elytrium.serializer.annotations.CommentValue;
4142
import net.elytrium.serializer.annotations.Final;
@@ -311,7 +312,8 @@ public String deserialize(String from) {
311312

312313
public List<String> regularList = Arrays.asList("123", "123", "456");
313314

314-
public Set<String> regularSet = new HashSet<>(Arrays.asList("123", "123", "456"));
315+
@CollectionType(HashSet.class)
316+
public Collection<String> regularSet = Arrays.asList("123", "123", "456");
315317

316318
public Deque<String> regularDeque = new ArrayDeque<>(Arrays.asList("123", "123", "456"));
317319

0 commit comments

Comments
 (0)