Skip to content

Commit 37fd1ea

Browse files
committed
Add overloaded methods for tag conversion
1 parent 59e0268 commit 37fd1ea

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

mapper/mapper-bukkit/src/main/java/com/saicone/nbt/mapper/BukkitTagMapper.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
import java.lang.invoke.MethodType;
1313
import java.lang.reflect.Constructor;
1414
import java.lang.reflect.Field;
15+
import java.util.ArrayList;
1516
import java.util.Collection;
17+
import java.util.HashMap;
1618
import java.util.List;
1719
import java.util.Map;
1820
import java.util.function.Function;
@@ -639,6 +641,34 @@ public Object build(@NotNull TagType<?> type, @Nullable Object object) {
639641
}
640642
}
641643

644+
@Override
645+
public Object parse(@NotNull List<?> list) {
646+
if (CACHE_COMPATIBLE && !list.isEmpty() && isType(list.get(0))) {
647+
// Check if list is mutable
648+
try {
649+
list.addAll(List.of());
650+
return build(TagType.LIST, list);
651+
} catch (UnsupportedOperationException e) {
652+
return build(TagType.LIST, new ArrayList<>(list));
653+
}
654+
}
655+
return TagMapper.super.parse(list);
656+
}
657+
658+
@Override
659+
public Object parse(@NotNull Map<String, ?> map) {
660+
if (CACHE_COMPATIBLE && !map.isEmpty() && isType(map.values().iterator().next())) {
661+
// Check if map is mutable
662+
try {
663+
map.putAll(Map.of());
664+
return build(TagType.COMPOUND, map);
665+
} catch (UnsupportedOperationException e) {
666+
return build(TagType.COMPOUND, new HashMap<>(map));
667+
}
668+
}
669+
return TagMapper.super.parse(map);
670+
}
671+
642672
@Override
643673
public Object extract(@Nullable Object object) {
644674
if (object == null) {

mapper/mapper-cloudburst/src/main/java/com/saicone/nbt/mapper/CloudburstTagMapper.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ public Object build(@NotNull TagType<?> type, @Nullable Object object) {
3737
}
3838
}
3939

40+
@Override
41+
public Object parse(@Nullable Object object) {
42+
if (object instanceof NbtList || object instanceof NbtMap) {
43+
return object;
44+
}
45+
return parse(TagType.getType(object), object);
46+
}
47+
48+
@Override
49+
public Object extract(@Nullable Object object) {
50+
return object;
51+
}
52+
4053
@Override
4154
@SuppressWarnings("unchecked")
4255
public int size(@Nullable Object object) {

mapper/mapper-minecraft/src/main/java/com/saicone/nbt/mapper/MinecraftTagMapper.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,20 @@ public Tag build(@NotNull TagType<?> type, @Nullable Object object) {
105105
}
106106
}
107107

108+
@Override
109+
public Tag parse(@NotNull List<?> list) {
110+
if (!list.isEmpty() && isType(list.get(0))) {
111+
// Check if list is mutable
112+
try {
113+
list.addAll(List.of());
114+
return build(TagType.LIST, list);
115+
} catch (UnsupportedOperationException e) {
116+
return build(TagType.LIST, new ArrayList<>(list));
117+
}
118+
}
119+
return TagMapper.super.parse(list);
120+
}
121+
108122
@Override
109123
public Object extract(@Nullable Tag tag) {
110124
if (tag == null) {

src/main/java/com/saicone/nbt/TagMapper.java

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import org.jetbrains.annotations.NotNull;
44
import org.jetbrains.annotations.Nullable;
55

6+
import java.util.ArrayList;
7+
import java.util.HashMap;
68
import java.util.Iterator;
79
import java.util.List;
810
import java.util.Map;
@@ -35,6 +37,16 @@ default boolean isType(@Nullable Object object) {
3537
return true;
3638
}
3739

40+
/**
41+
* Create a tag object from its value represented as java object.
42+
*
43+
* @param object the object value to convert.
44+
* @return a tag object containing the object value.
45+
*/
46+
default T build(@Nullable Object object) {
47+
return build(TagType.getType(object), object);
48+
}
49+
3850
/**
3951
* Create a tag object from its value represented as java object.
4052
*
@@ -44,6 +56,18 @@ default boolean isType(@Nullable Object object) {
4456
*/
4557
T build(@NotNull TagType<?> type, @Nullable Object object);
4658

59+
/**
60+
* Create an unchecked tag object from its value represented as java object.<br>
61+
* This method assumes that the required object is the type of that is returned.
62+
*
63+
* @param object the object value to convert.
64+
* @return an unchecked tag object containing the object value.
65+
* @param <A> the implementation of tag object.
66+
*/
67+
default <A extends T> A buildAny(@Nullable Object object) {
68+
return buildAny(TagType.getType(object), object);
69+
}
70+
4771
/**
4872
* Create an unchecked tag object from its value represented as java object.<br>
4973
* This method assumes that the required object is the type of that is returned.
@@ -58,6 +82,104 @@ default <A extends T> A buildAny(@NotNull TagType<?> type, @Nullable Object obje
5882
return (A) build(type, object);
5983
}
6084

85+
/**
86+
* Convert the provided value and any inner element to tag object if it isn't a tag type.<br>
87+
* This method safely convert any unmodifiable list or map into a required one.
88+
*
89+
* @param object the object value to convert.
90+
* @return a tag object containing the object value.
91+
*/
92+
@SuppressWarnings("unchecked")
93+
default T parse(@Nullable Object object) {
94+
if (isType(object)) {
95+
return (T) object;
96+
}
97+
return parse(TagType.getType(object), object);
98+
}
99+
100+
/**
101+
* Convert the provided list and any inner element to tag object.<br>
102+
* This method safely convert any unmodifiable list into a required one.
103+
*
104+
* @param list the list to convert.
105+
* @return a list tag object containing the list value or elements.
106+
*/
107+
default T parse(@NotNull List<?> list) {
108+
if (!list.isEmpty() && !isType(list.get(0))) {
109+
final List<T> tagList = new ArrayList<>();
110+
for (Object element : list) {
111+
tagList.add(parse(element));
112+
}
113+
return build(TagType.LIST, tagList);
114+
}
115+
return build(TagType.LIST, list);
116+
}
117+
118+
/**
119+
* Convert the provided map and any inner value to tag object.<br>
120+
* This method safely convert any unmodifiable map into a required one.
121+
*
122+
* @param map the map to convert.
123+
* @return a compound tag object containing the map value or entries.
124+
*/
125+
default T parse(@NotNull Map<String, ?> map) {
126+
if (!map.isEmpty() && !isType(map.values().iterator().next())) {
127+
final Map<String, T> compound = new HashMap<>();
128+
for (Map.Entry<String, ?> entry : map.entrySet()) {
129+
compound.put(entry.getKey(), parse(entry.getValue()));
130+
}
131+
return build(TagType.COMPOUND, compound);
132+
}
133+
return build(TagType.COMPOUND, map);
134+
}
135+
136+
/**
137+
* Convert the provided value and any inner element to tag object.<br>
138+
* This method safely convert any unmodifiable list or map into a required one.
139+
*
140+
* @param type the type of tag that will be converted.
141+
* @param object the object value to convert.
142+
* @return a tag object containing the object value.
143+
*/
144+
@SuppressWarnings("unchecked")
145+
default T parse(@NotNull TagType<?> type, @Nullable Object object) {
146+
if (type == TagType.LIST) {
147+
return parse((List<?>) object);
148+
} else if (type == TagType.COMPOUND) {
149+
return parse((Map<String, ?>) object);
150+
}
151+
return build(type, object);
152+
}
153+
154+
/**
155+
* Create an unchecked tag object from the provided value and any inner element if it isn't a tag type.<br>
156+
* This method assumes that the required object is the type of that is returned
157+
* and also safely convert any unmodifiable list or map into a required one.
158+
*
159+
* @param object the object value to convert.
160+
* @return a tag object containing the object value.
161+
* @param <A> the implementation of tag object.
162+
*/
163+
@SuppressWarnings("unchecked")
164+
default <A extends T> A parseAny(@Nullable Object object) {
165+
return (A) parse(object);
166+
}
167+
168+
/**
169+
* Create an unchecked tag object from the provided value and any inner element.<br>
170+
* This method assumes that the required object is the type of that is returned
171+
* and also safely convert any unmodifiable list or map into a required one.
172+
*
173+
* @param type the type of tag that will be converted.
174+
* @param object the object value to convert.
175+
* @return a tag object containing the object value.
176+
* @param <A> the implementation of tag object.
177+
*/
178+
@SuppressWarnings("unchecked")
179+
default <A extends T> A parseAny(@NotNull TagType<?> type, @Nullable Object object) {
180+
return (A) parse(type, object);
181+
}
182+
61183
/**
62184
* Extracts the inner value that tag object implementation contains.
63185
*
@@ -77,6 +199,33 @@ default Object extract(@Nullable T t) {
77199
return t;
78200
}
79201

202+
/**
203+
* Deeply extract the inner value that tag object implementation
204+
* contains and it's elements if inner value it is a List or Map.
205+
*
206+
* @param t the tag object.
207+
* @return a java value any inner element as java value that was represented from tag object.
208+
*/
209+
@SuppressWarnings("unchecked")
210+
default Object deepExtract(@Nullable T t) {
211+
final Object value = extract(t);
212+
if (value instanceof List) {
213+
final List<Object> list = new ArrayList<>();
214+
for (T element : (List<T>) value) {
215+
list.add(deepExtract(element));
216+
}
217+
return list;
218+
} else if (value instanceof Map) {
219+
final Map<String, Object> map = new HashMap<>();
220+
for (Map.Entry<String, T> entry : ((Map<String, T>) value).entrySet()) {
221+
map.put(entry.getKey(), deepExtract(entry.getValue()));
222+
}
223+
return map;
224+
} else {
225+
return value;
226+
}
227+
}
228+
80229
/**
81230
* Get the size of bytes from tag object implementation.
82231
*

0 commit comments

Comments
 (0)