SPIGOT-7804: Fix written book serialization
* Account for null/missing values when deserializing the 'resolved' and 'generation' fields. * Serialize the book pages as JSON strings. * Avoid redundant conversion from strings to components to JSON and back to components during deserialization. Add CraftChatMessage.fromJSONOrString that accepts a maxLength argument and remove the no longer used fromJSONOrStringToJSON, fromStringToJSON, and fromJSONComponent helper methods.
This commit is contained in:
parent
aac911d263
commit
62e3b73a49
@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.inventory;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,8 +36,7 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta {
|
|||||||
|
|
||||||
protected String title;
|
protected String title;
|
||||||
protected String author;
|
protected String author;
|
||||||
// We store the pages in their raw original text representation. See SPIGOT-5063, SPIGOT-5350, SPIGOT-3206
|
// Stored as components and serialized as JSON. See SPIGOT-5063, SPIGOT-5350, SPIGOT-3206
|
||||||
// For written books (CraftMetaBookSigned) the pages are stored in Minecraft's JSON format.
|
|
||||||
protected List<IChatBaseComponent> pages; // null and empty are two different states internally
|
protected List<IChatBaseComponent> pages; // null and empty are two different states internally
|
||||||
protected boolean resolved;
|
protected boolean resolved;
|
||||||
protected int generation;
|
protected int generation;
|
||||||
@ -105,13 +105,13 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta {
|
|||||||
this.pages = new ArrayList<IChatBaseComponent>();
|
this.pages = new ArrayList<IChatBaseComponent>();
|
||||||
for (Object page : pages) {
|
for (Object page : pages) {
|
||||||
if (page instanceof String) {
|
if (page instanceof String) {
|
||||||
internalAddPage(CraftChatMessage.fromJSON(CraftChatMessage.fromJSONOrStringToJSON((String) page, false, true, MAX_PAGE_LENGTH, false)));
|
internalAddPage(CraftChatMessage.fromJSONOrString((String) page, false, true, MAX_PAGE_LENGTH, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolved = SerializableMeta.getObject(Boolean.class, map, RESOLVED.BUKKIT, true);
|
resolved = SerializableMeta.getBoolean(map, RESOLVED.BUKKIT);
|
||||||
generation = SerializableMeta.getObject(Integer.class, map, GENERATION.BUKKIT, true);
|
generation = SerializableMeta.getInteger(map, GENERATION.BUKKIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -351,7 +351,7 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pages != null) {
|
if (pages != null) {
|
||||||
builder.put(BOOK_PAGES.BUKKIT, ImmutableList.copyOf(pages));
|
builder.put(BOOK_PAGES.BUKKIT, ImmutableList.copyOf(Lists.transform(pages, CraftChatMessage::toJSON)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
|
@ -96,6 +96,11 @@ public final class SerializableMeta implements ConfigurationSerializable {
|
|||||||
return value != null && value;
|
return value != null && value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getInteger(Map<?, ?> map, Object field) {
|
||||||
|
Integer value = getObject(Integer.class, map, field, true);
|
||||||
|
return value != null ? value : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> T getObject(Class<T> clazz, Map<?, ?> map, Object field, boolean nullable) {
|
public static <T> T getObject(Class<T> clazz, Map<?, ?> map, Object field, boolean nullable) {
|
||||||
final Object object = map.get(field);
|
final Object object = map.get(field);
|
||||||
|
|
||||||
|
@ -231,51 +231,26 @@ public final class CraftChatMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static IChatBaseComponent fromJSONOrString(String message, boolean nullable, boolean keepNewlines) {
|
public static IChatBaseComponent fromJSONOrString(String message, boolean nullable, boolean keepNewlines) {
|
||||||
|
return fromJSONOrString(message, nullable, keepNewlines, Integer.MAX_VALUE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IChatBaseComponent fromJSONOrString(String message, boolean nullable, boolean keepNewlines, int maxLength, boolean checkJsonContentLength) {
|
||||||
if (message == null) message = "";
|
if (message == null) message = "";
|
||||||
if (nullable && message.isEmpty()) return null;
|
if (nullable && message.isEmpty()) return null;
|
||||||
IChatBaseComponent component = fromJSONOrNull(message);
|
IChatBaseComponent component = fromJSONOrNull(message);
|
||||||
if (component != null) {
|
|
||||||
return component;
|
|
||||||
} else {
|
|
||||||
return fromString(message, keepNewlines)[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromJSONOrStringToJSON(String message) {
|
|
||||||
return fromJSONOrStringToJSON(message, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromJSONOrStringToJSON(String message, boolean keepNewlines) {
|
|
||||||
return fromJSONOrStringToJSON(message, false, keepNewlines, Integer.MAX_VALUE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromJSONOrStringOrNullToJSON(String message) {
|
|
||||||
return fromJSONOrStringOrNullToJSON(message, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromJSONOrStringOrNullToJSON(String message, boolean keepNewlines) {
|
|
||||||
return fromJSONOrStringToJSON(message, true, keepNewlines, Integer.MAX_VALUE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromJSONOrStringToJSON(String message, boolean nullable, boolean keepNewlines, int maxLength, boolean checkJsonContentLength) {
|
|
||||||
if (message == null) message = "";
|
|
||||||
if (nullable && message.isEmpty()) return null;
|
|
||||||
// If the input can be parsed as JSON, we use that:
|
|
||||||
IChatBaseComponent component = fromJSONOrNull(message);
|
|
||||||
if (component != null) {
|
if (component != null) {
|
||||||
if (checkJsonContentLength) {
|
if (checkJsonContentLength) {
|
||||||
String content = fromComponent(component);
|
String content = fromComponent(component);
|
||||||
String trimmedContent = trimMessage(content, maxLength);
|
String trimmedContent = trimMessage(content, maxLength);
|
||||||
if (content != trimmedContent) { // identity comparison is fine here
|
if (content != trimmedContent) { // Identity comparison is fine here
|
||||||
// Note: The resulting text has all non-plain text features stripped.
|
// Note: The resulting text has all non-plain text features stripped.
|
||||||
return fromStringToJSON(trimmedContent, keepNewlines);
|
return fromString(trimmedContent, keepNewlines)[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return message;
|
return component;
|
||||||
} else {
|
} else {
|
||||||
// Else we interpret the input as legacy text:
|
|
||||||
message = trimMessage(message, maxLength);
|
message = trimMessage(message, maxLength);
|
||||||
return fromStringToJSON(message, keepNewlines);
|
return fromString(message, keepNewlines)[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,25 +262,6 @@ public final class CraftChatMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String fromStringToJSON(String message) {
|
|
||||||
return fromStringToJSON(message, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromStringToJSON(String message, boolean keepNewlines) {
|
|
||||||
IChatBaseComponent component = CraftChatMessage.fromString(message, keepNewlines)[0];
|
|
||||||
return CraftChatMessage.toJSON(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromStringOrNullToJSON(String message) {
|
|
||||||
IChatBaseComponent component = CraftChatMessage.fromStringOrNull(message);
|
|
||||||
return CraftChatMessage.toJSONOrNull(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromJSONComponent(String jsonMessage) {
|
|
||||||
IChatBaseComponent component = CraftChatMessage.fromJSONOrNull(jsonMessage);
|
|
||||||
return CraftChatMessage.fromComponent(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String fromComponent(IChatBaseComponent component) {
|
public static String fromComponent(IChatBaseComponent component) {
|
||||||
if (component == null) return "";
|
if (component == null) return "";
|
||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user