diff --git a/core/src/main/java/org/parchmentmc/feather/mapping/ImmutableMappingDataContainer.java b/core/src/main/java/org/parchmentmc/feather/mapping/ImmutableMappingDataContainer.java index 3dd57ba..a474d94 100644 --- a/core/src/main/java/org/parchmentmc/feather/mapping/ImmutableMappingDataContainer.java +++ b/core/src/main/java/org/parchmentmc/feather/mapping/ImmutableMappingDataContainer.java @@ -215,11 +215,14 @@ public static class ImmutableFieldData implements MappingDataContainer.FieldData private final String name; private final String descriptor; private final List javadoc; + @Nullable + private final ConstantData constant; - public ImmutableFieldData(String name, String descriptor, List javadoc) { + public ImmutableFieldData(String name, String descriptor, List javadoc, @Nullable ConstantData constant) { this.name = name; this.descriptor = descriptor; this.javadoc = ImmutableList.copyOf(javadoc); + this.constant = constant; } /** @@ -246,18 +249,36 @@ public List getJavadoc() { return javadoc; } + /** + * {@inheritDoc} + */ + @Override + public ConstantData getConstant() { + return constant; + } + @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof FieldData)) return false; - FieldData that = (FieldData) o; - return getName().equals(that.getName()) && Objects.equals(getDescriptor(), that.getDescriptor()) - && getJavadoc().equals(that.getJavadoc()); + if (!(o instanceof ImmutableFieldData)) return false; + + ImmutableFieldData that = (ImmutableFieldData) o; + + if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) return false; + if (getDescriptor() != null ? !getDescriptor().equals(that.getDescriptor()) : that.getDescriptor() != null) + return false; + if (getJavadoc() != null ? !getJavadoc().equals(that.getJavadoc()) : that.getJavadoc() != null) + return false; + return getConstant() != null ? getConstant().equals(that.getConstant()) : that.getConstant() == null; } @Override public int hashCode() { - return Objects.hash(getName(), getDescriptor(), getJavadoc()); + int result = getName() != null ? getName().hashCode() : 0; + result = 31 * result + (getDescriptor() != null ? getDescriptor().hashCode() : 0); + result = 31 * result + (getJavadoc() != null ? getJavadoc().hashCode() : 0); + result = 31 * result + (getConstant() != null ? getConstant().hashCode() : 0); + return result; } } @@ -344,11 +365,14 @@ public static class ImmutableParameterData implements MappingDataContainer.Param private final String name; @Nullable private final String javadoc; + @Nullable + private final ConstantData constant; - public ImmutableParameterData(byte index, @Nullable String name, @Nullable String javadoc) { + public ImmutableParameterData(byte index, @Nullable String name, @Nullable String javadoc, @Nullable ConstantData constant) { this.index = index; this.name = name; this.javadoc = javadoc; + this.constant = constant; } /** @@ -377,17 +401,131 @@ public String getJavadoc() { return javadoc; } + /** + * {@inheritDoc} + */ + @Override + public ConstantData getConstant() { + return constant; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ImmutableParameterData)) return false; + + ImmutableParameterData that = (ImmutableParameterData) o; + + if (getIndex() != that.getIndex()) return false; + if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) return false; + if (getJavadoc() != null ? !getJavadoc().equals(that.getJavadoc()) : that.getJavadoc() != null) + return false; + return getConstant() != null ? getConstant().equals(that.getConstant()) : that.getConstant() == null; + } + + @Override + public int hashCode() { + int result = getIndex(); + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + (getJavadoc() != null ? getJavadoc().hashCode() : 0); + result = 31 * result + (getConstant() != null ? getConstant().hashCode() : 0); + return result; + } + } + + /** + * An immutable {@link MappingDataContainer.ConstantData}. + */ + public static final class ImmutableConstantData implements ConstantData { + + private final ConstantType type; + private final List values; + + public ImmutableConstantData(ConstantType type, List values) { + this.type = type; + this.values = values; + } + + /** + * {@inheritDoc} + */ + @Override + public ConstantType getType() { + return type; + } + + /** + * {@inheritDoc} + */ + @Override + public List getValues() { + return values; + } + @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ParameterData)) return false; - ParameterData that = (ParameterData) o; - return getIndex() == that.getIndex() && Objects.equals(getName(), that.getName()) && Objects.equals(getJavadoc(), that.getJavadoc()); + if (!(o instanceof ImmutableConstantData)) return false; + + ImmutableConstantData that = (ImmutableConstantData) o; + + if (getType() != that.getType()) return false; + return getValues().equals(that.getValues()); + } + + @Override + public int hashCode() { + int result = getType().hashCode(); + result = 31 * result + getValues().hashCode(); + return result; + } + } + + /** + * An immutable {@link MappingDataContainer.ConstantValueData}. + */ + public static final class ImmutableConstantValueData implements ConstantValueData { + + private final int value; + private final String reference; + + public ImmutableConstantValueData(int value, String reference) { + this.value = value; + this.reference = reference; + } + + /** + * {@inheritDoc} + */ + @Override + public int getValue() { + return value; + } + + /** + * {@inheritDoc} + */ + @Override + public String getReference() { + return reference; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ImmutableConstantValueData)) return false; + + ImmutableConstantValueData that = (ImmutableConstantValueData) o; + + if (getValue() != that.getValue()) return false; + return getReference().equals(that.getReference()); } @Override public int hashCode() { - return Objects.hash(getIndex(), getName(), getJavadoc()); + int result = getValue(); + result = 31 * result + getReference().hashCode(); + return result; } } } diff --git a/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataBuilder.java b/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataBuilder.java index 88d2c6a..9cfec4f 100644 --- a/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataBuilder.java +++ b/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataBuilder.java @@ -125,6 +125,53 @@ default T addJavadoc(String... line) { T clearJavadoc(); } + public interface MutableHasConstants extends MutableHasConstantValues, CanContainConstantValue { + @Override + @Nullable + MutableConstantData getConstant(); + + T setConstant(@Nullable ConstantData constantData); + + @Override + default List getConstantValues() { + final MappingDataContainer.ConstantData constantData = this.getConstant(); + if (constantData == null) { + setConstant(new MutableConstantData()); + return getConstantValues(); + } + + return constantData.getValues(); + } + } + + public interface MutableHasConstantValues { + default T addConstantValue(ConstantValueData value) { + final List values = this.getConstantValues(); + if (!values.contains(value)) { + values.add(value); + } + return setConstantValues(values); + } + + default T removeConstantValue(ConstantValueData value) { + final List values = this.getConstantValues(); + values.remove(value); + return setConstantValues(values); + } + + default T addConstantValue(int value, String reference) { + return addConstantValue(new MutableConstantValueData(value, reference)); + } + + default T removeConstantValue(int value, String reference) { + return removeConstantValue(new MutableConstantValueData(value, reference)); + } + + List getConstantValues(); + + T setConstantValues(List values); + } + public static class MutablePackageData implements MappingDataContainer.PackageData, MutableHasJavadoc { private final String name; private final List javadoc = new ArrayList<>(); @@ -309,10 +356,11 @@ public int hashCode() { } } - public static class MutableFieldData implements MappingDataContainer.FieldData, MutableHasJavadoc { + public static class MutableFieldData implements MappingDataContainer.FieldData, MutableHasJavadoc, MutableHasConstants { private final String name; private final String descriptor; private final List javadoc = new ArrayList<>(); + private MutableConstantData constant; private transient final List javadocView = Collections.unmodifiableList(javadoc); MutableFieldData(String name, String descriptor) { @@ -347,18 +395,56 @@ public MutableFieldData clearJavadoc() { return this; } + @Override + public MutableConstantData getConstant() { + return constant; + } + + @Override + public MutableFieldData setConstant(@Nullable ConstantData constantData) { + if (constantData == null) { + this.constant = null; + } else { + this.constant = new MutableConstantData(constantData); + } + return this; + } + + @Override + public MutableFieldData setConstantValues(List values) { + if (this.constant == null) { + this.constant = new MutableConstantData(); + } + + this.constant.setConstantValues(values); + return this; + } + @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof FieldData)) return false; - FieldData that = (FieldData) o; - return getName().equals(that.getName()) && Objects.equals(getDescriptor(), that.getDescriptor()) - && getJavadoc().equals(that.getJavadoc()); + if (!(o instanceof MutableFieldData)) return false; + + MutableFieldData that = (MutableFieldData) o; + + if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) return false; + if (getDescriptor() != null ? !getDescriptor().equals(that.getDescriptor()) : that.getDescriptor() != null) + return false; + if (getJavadoc() != null ? !getJavadoc().equals(that.getJavadoc()) : that.getJavadoc() != null) + return false; + if (getConstant() != null ? !getConstant().equals(that.getConstant()) : that.getConstant() != null) + return false; + return Objects.equals(javadocView, that.javadocView); } @Override public int hashCode() { - return Objects.hash(getName(), getDescriptor(), getJavadoc()); + int result = getName() != null ? getName().hashCode() : 0; + result = 31 * result + (getDescriptor() != null ? getDescriptor().hashCode() : 0); + result = 31 * result + (getJavadoc() != null ? getJavadoc().hashCode() : 0); + result = 31 * result + (getConstant() != null ? getConstant().hashCode() : 0); + result = 31 * result + (javadocView != null ? javadocView.hashCode() : 0); + return result; } } @@ -458,12 +544,13 @@ public int hashCode() { } } - public static class MutableParameterData implements MappingDataContainer.ParameterData, MutableHasJavadoc { + public static class MutableParameterData implements MappingDataContainer.ParameterData, MutableHasJavadoc, MutableHasConstants { private final byte index; @Nullable private String name = null; @Nullable private String javadoc = null; + private MutableConstantData constant = null; MutableParameterData(byte index) { this.index = index; @@ -496,29 +583,163 @@ public MutableParameterData setJavadoc(@Nullable String javadoc) { return this; } + @Override + public MutableParameterData addJavadoc(Collection lines) { + this.javadoc = lines.stream().findFirst().orElse(null); + return this; + } + + @Override + public MutableParameterData clearJavadoc() { + this.javadoc = null; + return this; + } + + @Override + public @Nullable MutableConstantData getConstant() { + return constant; + } + + @Override + public MutableParameterData setConstant(@Nullable ConstantData constantData) { + if (constantData == null) { + this.constant = null; + } else { + this.constant = new MutableConstantData(constantData); + } + + return this; + } + + @Override + public MutableParameterData setConstantValues(List values) { + if (this.constant == null) + this.constant = new MutableConstantData(); + + this.constant.setValues(values); + + return this; + } + } + + public static class MutableConstantData implements MappingDataContainer.ConstantData, MutableHasConstantValues { + + private ConstantType type; + private List values = new ArrayList<>(); + + public MutableConstantData(ConstantType type, List values) { + this.type = type; + this.values = values; + } + + public MutableConstantData(ConstantData from) { + this(from.getType(), new ArrayList<>(from.getValues())); + } + + public MutableConstantData() { + } + + @Override + public ConstantType getType() { + return type; + } + + @Override + public List getValues() { + return values; + } + + public MutableConstantData setValues(List values) { + this.values = values; + return this; + } + + public MutableConstantData setType(ConstantType type) { + this.type = type; + return this; + } + + @Override + public List getConstantValues() { + return values; + } + + @Override + public MutableConstantData setConstantValues(List values) { + this.values = values; + return this; + } + @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ParameterData)) return false; - ParameterData that = (ParameterData) o; - return getIndex() == that.getIndex() && Objects.equals(getName(), that.getName()) && Objects.equals(getJavadoc(), that.getJavadoc()); + if (!(o instanceof MutableConstantData)) return false; + + MutableConstantData that = (MutableConstantData) o; + + if (getType() != that.getType()) return false; + return getValues() != null ? getValues().equals(that.getValues()) : that.getValues() == null; } @Override public int hashCode() { - return Objects.hash(getIndex(), getName(), getJavadoc()); + int result = getType() != null ? getType().hashCode() : 0; + result = 31 * result + (getValues() != null ? getValues().hashCode() : 0); + return result; + } + } + + public static class MutableConstantValueData implements MappingDataContainer.ConstantValueData { + + private int value; + private String reference; + + public MutableConstantValueData(int value, String reference) { + this.value = value; + this.reference = reference; + } + + public MutableConstantValueData(MappingDataContainer.ConstantValueData from) { + this(from.getValue(), from.getReference()); + } + + public MutableConstantValueData() { } @Override - public MutableParameterData addJavadoc(Collection lines) { - this.javadoc = lines.stream().findFirst().orElse(null); - return this; + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; } @Override - public MutableParameterData clearJavadoc() { - this.javadoc = null; - return this; + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MutableConstantValueData)) return false; + + MutableConstantValueData that = (MutableConstantValueData) o; + + if (getValue() != that.getValue()) return false; + return getReference() != null ? getReference().equals(that.getReference()) : that.getReference() == null; + } + + @Override + public int hashCode() { + int result = getValue(); + result = 31 * result + (getReference() != null ? getReference().hashCode() : 0); + return result; } } } diff --git a/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataContainer.java b/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataContainer.java index eb94fd9..35066a9 100644 --- a/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataContainer.java +++ b/core/src/main/java/org/parchmentmc/feather/mapping/MappingDataContainer.java @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; +import java.util.Optional; /** * A container for mapping data, for packages, classes, methods, fields, and parameters. @@ -167,7 +168,7 @@ interface ClassData { * * @see ClassData */ - interface FieldData { + interface FieldData extends CanContainConstantValue { Comparator COMPARATOR = Comparator.comparing(FieldData::getName); /** @@ -292,7 +293,7 @@ interface MethodData { * * @see MethodData */ - interface ParameterData { + interface ParameterData extends CanContainConstantValue { Comparator COMPARATOR = Comparator.comparing(ParameterData::getIndex); /** @@ -336,4 +337,90 @@ interface ParameterData { @Nullable String getJavadoc(); } + + + /** + * Indicates that this member can contain constant values. + */ + interface CanContainConstantValue { + /** + * Returns the constants data for this parameter, if it can be determined. + * Only members with a {@link int}, {@link long} or {@link boolean} type can have constants data. + *

+ * The returned optional HAS to be empty if the member is not of one of the listed types, + * if this method would return a none empty optional for a member of a different type, + * then the returned optional SHOULD be ignored. + *

+ * Data related to constants can be used to "unpick" the constant value of this member. + * Allowing for example the value 3 to be decoded to the two constants {@code 1 + 2} or {@code 2 + 1} + * which are then combined using a bitwise or. The location of these two constants can be retrieved + * from {@link MappingDataContainer.ConstantData#getValues()}, by checking the {@link MappingDataContainer.ConstantData#getType()} and + * {@link MappingDataContainer.ConstantValueData#getValue()} of each possible constant value. + * + * @return the constants data for this member, if it is available and applicable. + */ + @Nullable + ConstantData getConstant(); + } + + /** + * Defines the data for the use of constants related to {@link FieldData} or {@link ParameterData}. + * Their use is defined by the {@link ConstantType} enum. + * The data also gives access to a list of possible values of the constants that are known. + */ + interface ConstantData { + Comparator COMPARATOR = Comparator.comparing(ConstantData::getType); + + /** + * Returns the constant type of this constant. + * + * @return the constant type + */ + ConstantType getType(); + + /** + * Returns a list of all the constant values. + * + * @return the list of constant values + */ + List getValues(); + } + + /** + * Defines the data for a single possible constant value. + */ + interface ConstantValueData { + Comparator COMPARATOR = Comparator.comparing(ConstantValueData::getValue); + + /** + * Returns the value of the constant. + * For {@link ConstantType#FLAG} constants, this is the bit value in readable integer, so 1, 2, 4, 8, 16, etc. + * For {@link ConstantType#CONSTANT} constants, this is the value of the constant. + * + * @return the value of the constant + */ + int getValue(); + + /** + * Returns the fully qualified name of the static field that the constant is stored in. + * + * @return the fully qualified name of the static field + */ + String getReference(); + } + + /** + * The constant value type. + */ + enum ConstantType { + /** + * Indicates that this member contains a bit wise combined binary values indicating different flags. + */ + FLAG, + /** + * Indicates that this member contains a constant value. + */ + CONSTANT + } + } diff --git a/core/src/main/java/org/parchmentmc/feather/mapping/MappingUtil.java b/core/src/main/java/org/parchmentmc/feather/mapping/MappingUtil.java index 5c85912..7132d1a 100644 --- a/core/src/main/java/org/parchmentmc/feather/mapping/MappingUtil.java +++ b/core/src/main/java/org/parchmentmc/feather/mapping/MappingUtil.java @@ -22,14 +22,28 @@ static MappingDataBuilder copyData(MappingDataContainer container) { MutableClassData classData = builder.createClass(cls.getName()).addJavadoc(cls.getJavadoc()); // Copy fields - cls.getFields().forEach(field -> classData.createField(field.getName(), field.getDescriptor()).addJavadoc(field.getJavadoc())); + cls.getFields().forEach(field -> { + final MappingDataBuilder.MutableFieldData fieldData = classData.createField(field.getName(), field.getDescriptor()).addJavadoc(field.getJavadoc()); + + //Copy constant + if (field.getConstant() != null) { + fieldData.setConstant(new MappingDataBuilder.MutableConstantData(field.getConstant())); + } + }); // Copy methods cls.getMethods().forEach(method -> { MutableMethodData methodData = classData.createMethod(method.getName(), method.getDescriptor()).addJavadoc(method.getJavadoc()); // Copy parameters - method.getParameters().forEach(param -> methodData.createParameter(param.getIndex()).setName(param.getName()).setJavadoc(param.getJavadoc())); + method.getParameters().forEach(param -> { + final MappingDataBuilder.MutableParameterData parameterData = methodData.createParameter(param.getIndex()).setName(param.getName()).setJavadoc(param.getJavadoc()); + + //Copy constant + if (param.getConstant() != null) { + parameterData.setConstant(new MappingDataBuilder.MutableConstantData(param.getConstant())); + } + }); }); }); @@ -42,9 +56,9 @@ static MappingDataBuilder copyData(MappingDataContainer container) { * *

All entries from the base mapping data is copied over to the resulting mapping data container.

* - *

If an entry in the base mapping data has a corresponding entry in the new mapping data, the javadocs (and - * names for parameters) from the new mapping data entry is used; otherwise, the javadocs (and parameter names) - * from the base mapping data is used.

+ *

If an entry in the base mapping data has a corresponding entry in the new mapping data, the javadocs, + * names for parameters and the constant data from the new mapping data entry is used; otherwise, + * the data from the base mapping data is used.

* *

If a {@link ClassData class entry} from the new mapping data is present in the base mapping data, * all new fields and methods (including parameters) from the new mapping data is copied over. Likewise, if @@ -71,10 +85,10 @@ public static MappingDataContainer apply(MappingDataContainer baseData, MappingD .addJavadoc(newCls != null ? newCls.getJavadoc() : cls.getJavadoc()); cls.getFields().forEach(field -> { - FieldData newField = newCls != null ? newCls.getField(field.getName()) : null; classData.createField(field.getName(), field.getDescriptor()) - .addJavadoc(newField != null ? newField.getJavadoc() : field.getJavadoc()); + .addJavadoc(newField != null ? newField.getJavadoc() : field.getJavadoc()) + .setConstant(newField != null ? newField.getConstant() : field.getConstant()); }); cls.getMethods().forEach(method -> { @@ -86,12 +100,13 @@ public static MappingDataContainer apply(MappingDataContainer baseData, MappingD ParameterData newParam = newMethod != null ? newMethod.getParameter(param.getIndex()) : null; methodData.createParameter(param.getIndex()) .setName(newParam != null ? newParam.getName() : param.getName()) - .setJavadoc(newParam != null ? newParam.getJavadoc() : param.getJavadoc()); + .setJavadoc(newParam != null ? newParam.getJavadoc() : param.getJavadoc()) + .setConstant(newParam != null ? newParam.getConstant() : param.getConstant()); }); if (newMethod != null) { newMethod.getParameters().forEach(param -> { if (method.getParameter(param.getIndex()) == null) - methodData.createParameter(param.getIndex()).setName(param.getName()).setJavadoc(param.getJavadoc()); + methodData.createParameter(param.getIndex()).setName(param.getName()).setJavadoc(param.getJavadoc()).setConstant(param.getConstant()); }); } }); diff --git a/core/src/test/java/org/parchmentmc/feather/manifests/MDCTestConstants.java b/core/src/test/java/org/parchmentmc/feather/manifests/MDCTestConstants.java index 7f4fee2..5d140c2 100644 --- a/core/src/test/java/org/parchmentmc/feather/manifests/MDCTestConstants.java +++ b/core/src/test/java/org/parchmentmc/feather/manifests/MDCTestConstants.java @@ -16,10 +16,10 @@ */ public interface MDCTestConstants { List PARAMETERS = of( - new ImmutableMappingDataContainer.ImmutableParameterData((byte) 1, "1testName", "1Some javadoc"), - new ImmutableMappingDataContainer.ImmutableParameterData((byte) 2, null, "2Some javadoc"), - new ImmutableMappingDataContainer.ImmutableParameterData((byte) 3, "3testName", null), - new ImmutableMappingDataContainer.ImmutableParameterData((byte) 4, null, null) + new ImmutableMappingDataContainer.ImmutableParameterData((byte) 1, "1testName", "1Some javadoc", null), + new ImmutableMappingDataContainer.ImmutableParameterData((byte) 2, null, "2Some javadoc", null), + new ImmutableMappingDataContainer.ImmutableParameterData((byte) 3, "3testName", null, null), + new ImmutableMappingDataContainer.ImmutableParameterData((byte) 4, null, null, null) ); List MULTILINE_JAVADOC = of("Some javadocs", "", "Multiline javadocs!"); @@ -32,9 +32,9 @@ public interface MDCTestConstants { ); List FIELDS = of( - new ImmutableMappingDataContainer.ImmutableFieldData("aField", "F", of()), - new ImmutableMappingDataContainer.ImmutableFieldData("anotherOne", "Ljava/util/Objects;", of()), - new ImmutableMappingDataContainer.ImmutableFieldData("thirdTimes", "Z", MULTILINE_JAVADOC) + new ImmutableMappingDataContainer.ImmutableFieldData("aField", "F", of(), null), + new ImmutableMappingDataContainer.ImmutableFieldData("anotherOne", "Ljava/util/Objects;", of(), null), + new ImmutableMappingDataContainer.ImmutableFieldData("thirdTimes", "Z", MULTILINE_JAVADOC, null) ); List CLASSES = of( diff --git a/io-gson/src/main/java/org/parchmentmc/feather/io/gson/MDCGsonAdapterFactory.java b/io-gson/src/main/java/org/parchmentmc/feather/io/gson/MDCGsonAdapterFactory.java index 8509f8c..3ae20b1 100644 --- a/io-gson/src/main/java/org/parchmentmc/feather/io/gson/MDCGsonAdapterFactory.java +++ b/io-gson/src/main/java/org/parchmentmc/feather/io/gson/MDCGsonAdapterFactory.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -63,7 +64,11 @@ public TypeAdapter create(Gson gson, TypeToken typeToken) { } else if (type.equals(MappingDataContainer.MethodData.class)) { return (TypeAdapter) new MethodDataAdapter(gson, ignoreNonDocumented).nullSafe(); } else if (type.equals(MappingDataContainer.ParameterData.class)) { - return (TypeAdapter) new ParameterDataAdapter(ignoreNonDocumented).nullSafe(); + return (TypeAdapter) new ParameterDataAdapter(gson, ignoreNonDocumented).nullSafe(); + } else if (type.equals(MappingDataContainer.ConstantData.class)) { + return (TypeAdapter) new ConstantDataAdapter(gson, ignoreNonDocumented).nullSafe(); + } else if (type.equals(MappingDataContainer.ConstantValueData.class)) { + return (TypeAdapter) new ConstantValueDataAdapter().nullSafe(); } return null; } @@ -304,6 +309,10 @@ public void write(JsonWriter writer, MappingDataContainer.FieldData fieldName) t writer.name("javadoc"); gson.getAdapter(STRING_LIST_TOKEN).write(writer, fieldName.getJavadoc()); } + if (fieldName.getConstant() != null) { + writer.name("constant"); + gson.getAdapter(MappingDataContainer.ConstantData.class).write(writer, fieldName.getConstant()); + } writer.endObject(); } @@ -312,6 +321,7 @@ public MappingDataContainer.FieldData read(JsonReader reader) throws IOException String name = null; String descriptor = null; List javadoc = null; + MappingDataContainer.ConstantData constant = null; reader.beginObject(); while (reader.hasNext()) { @@ -326,6 +336,9 @@ public MappingDataContainer.FieldData read(JsonReader reader) throws IOException case "javadoc": javadoc = gson.getAdapter(STRING_LIST_TOKEN).read(reader); break; + case "constant": + constant = gson.getAdapter(MappingDataContainer.ConstantData.class).read(reader); + break; default: reader.skipValue(); break; @@ -337,7 +350,7 @@ public MappingDataContainer.FieldData read(JsonReader reader) throws IOException if (descriptor == null) throw new IllegalArgumentException("Field descriptor must not be null"); if (javadoc == null) javadoc = Collections.emptyList(); - return new ImmutableMappingDataContainer.ImmutableFieldData(name, descriptor, javadoc); + return new ImmutableMappingDataContainer.ImmutableFieldData(name, descriptor, javadoc, constant); } } @@ -422,9 +435,11 @@ public MappingDataContainer.MethodData read(JsonReader reader) throws IOExceptio * GSON adapter for {@link MappingDataContainer.ParameterData}s. */ static class ParameterDataAdapter extends TypeAdapter { + private final Gson gson; private final boolean ignoreNonDocumented; - ParameterDataAdapter(boolean ignoreNonDocumented) { + ParameterDataAdapter(Gson gson, boolean ignoreNonDocumented) { + this.gson = gson; this.ignoreNonDocumented = ignoreNonDocumented; } @@ -443,6 +458,10 @@ public void write(JsonWriter writer, MappingDataContainer.ParameterData packageD if (packageData.getJavadoc() != null) { writer.name("javadoc").value(packageData.getJavadoc()); } + if (packageData.getConstant() != null) { + writer.name("constant"); + gson.getAdapter(MappingDataContainer.ConstantData.class).write(writer, packageData.getConstant()); + } writer.endObject(); } @@ -452,6 +471,7 @@ public MappingDataContainer.ParameterData read(JsonReader reader) throws IOExcep byte index = -1; String name = null; String javadoc = null; + MappingDataContainer.ConstantData constant = null; reader.beginObject(); while (reader.hasNext()) { @@ -466,6 +486,9 @@ public MappingDataContainer.ParameterData read(JsonReader reader) throws IOExcep case "javadoc": javadoc = reader.nextString(); break; + case "constant": + constant = gson.getAdapter(MappingDataContainer.ConstantData.class).read(reader); + break; default: reader.skipValue(); break; @@ -475,7 +498,103 @@ public MappingDataContainer.ParameterData read(JsonReader reader) throws IOExcep if (index < 0) throw new IllegalArgumentException("Parameter index must be present and positive"); - return new ImmutableMappingDataContainer.ImmutableParameterData(index, name, javadoc); + return new ImmutableMappingDataContainer.ImmutableParameterData(index, name, javadoc, constant); + } + } + + static class ConstantDataAdapter extends TypeAdapter { + static final TypeToken> CONSTANT_VALUE_DATA_COLLECTION = + new TypeToken>() { + }; + + private final Gson gson; + private final boolean ignoreNonDocumented; + + ConstantDataAdapter(Gson gson, boolean ignoreNonDocumented) { + this.gson = gson; + this.ignoreNonDocumented = ignoreNonDocumented; + } + + @Override + public void write(JsonWriter out, MappingDataContainer.ConstantData value) throws IOException { + out.beginObject(); + + out.name("type"); + gson.getAdapter(MappingDataContainer.ConstantType.class).write(out, value.getType()); + + out.name("values"); + gson.getAdapter(CONSTANT_VALUE_DATA_COLLECTION).write(out, value.getValues()); + + out.endObject(); + } + + @Override + public MappingDataContainer.ConstantData read(JsonReader in) throws IOException { + MappingDataContainer.ConstantType type = null; + Collection values = null; + + in.beginObject(); + while (in.hasNext()) { + String propertyName = in.nextName(); + switch (propertyName) { + case "type": + type = gson.getAdapter(MappingDataContainer.ConstantType.class).read(in); + break; + case "values": + values = gson.getAdapter(CONSTANT_VALUE_DATA_COLLECTION).read(in); + break; + default: + in.skipValue(); + break; + } + } + in.endObject(); + + if (type == null) throw new IllegalArgumentException("Field type must not be null"); + if (values == null) values = Collections.emptyList(); + + return new ImmutableMappingDataContainer.ImmutableConstantData(type, new ArrayList<>(values)); + } + } + + static class ConstantValueDataAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, MappingDataContainer.ConstantValueData value) throws IOException { + out.beginObject(); + + out.name("value").value(value.getValue()); + out.name("reference").value(value.getReference()); + + out.endObject(); + } + + @Override + public MappingDataContainer.ConstantValueData read(JsonReader in) throws IOException { + Integer value = null; + String reference = null; + + in.beginObject(); + while (in.hasNext()) { + String propertyName = in.nextName(); + switch (propertyName) { + case "value": + value = in.nextInt(); + break; + case "reference": + reference = in.nextString(); + break; + default: + in.skipValue(); + break; + } + } + in.endObject(); + + if (value == null) throw new IllegalArgumentException("Field value must not be null"); + if (reference == null) throw new IllegalArgumentException("Field reference must not be null"); + + return new ImmutableMappingDataContainer.ImmutableConstantValueData(value, reference); } } } diff --git a/io-moshi/src/main/java/org/parchmentmc/feather/io/moshi/MDCMoshiAdapter.java b/io-moshi/src/main/java/org/parchmentmc/feather/io/moshi/MDCMoshiAdapter.java index 5f43c29..4ef6132 100644 --- a/io-moshi/src/main/java/org/parchmentmc/feather/io/moshi/MDCMoshiAdapter.java +++ b/io-moshi/src/main/java/org/parchmentmc/feather/io/moshi/MDCMoshiAdapter.java @@ -8,6 +8,7 @@ import org.parchmentmc.feather.util.SimpleVersion; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -91,7 +92,8 @@ void classToJson(JsonWriter writer, @ToJson void fieldToJson(JsonWriter writer, MappingDataContainer.FieldData fieldData, - JsonAdapter> stringListAdapter) throws IOException { + JsonAdapter> stringListAdapter, + JsonAdapter constantDataAdapter) throws IOException { if (isIgnoreNonDocumented() && fieldData.getJavadoc().isEmpty()) return; writer.beginObject() @@ -99,6 +101,8 @@ void fieldToJson(JsonWriter writer, .name("descriptor").value(fieldData.getDescriptor()); if (!fieldData.getJavadoc().isEmpty()) writer.name("javadoc").jsonValue(stringListAdapter.toJsonValue(fieldData.getJavadoc())); + if (fieldData.getConstant() != null) + writer.name("constant").jsonValue(constantDataAdapter.toJsonValue(fieldData.getConstant())); writer.endObject(); } @@ -123,8 +127,9 @@ void methodToJson(JsonWriter writer, } @ToJson - void paramToJson(JsonWriter writer, - MappingDataContainer.ParameterData paramData) throws IOException { + void paramFromJson(JsonWriter writer, + MappingDataContainer.ParameterData paramData, + JsonAdapter constantDataAdapter) throws IOException { if (isIgnoreNonDocumented() && paramData.getName() == null && paramData.getJavadoc() == null) return; writer.beginObject() @@ -133,6 +138,32 @@ void paramToJson(JsonWriter writer, writer.name("name").value(paramData.getName()); if (paramData.getJavadoc() != null) writer.name("javadoc").value(paramData.getJavadoc()); + if (paramData.getConstant() != null) + writer.name("constant").jsonValue(constantDataAdapter.toJsonValue(paramData.getConstant())); + writer.endObject(); + } + + @ToJson + void constantToJson(JsonWriter writer, + MappingDataContainer.ConstantData constantData, + JsonAdapter constantTypeAdapter, + JsonAdapter> valueDataAdapter) throws IOException { + writer.beginObject(); + + writer.name("type").value(constantTypeAdapter.toJson(constantData.getType())); + writer.name("values").jsonValue(valueDataAdapter.toJsonValue(constantData.getValues())); + + writer.endObject(); + } + + @ToJson + void constantValueToJson(JsonWriter writer, + MappingDataContainer.ConstantValueData constantValueData) throws IOException { + writer.beginObject(); + + writer.name("value").value(constantValueData.getValue()); + writer.name("reference").value(constantValueData.getReference()); + writer.endObject(); } @@ -252,10 +283,12 @@ MappingDataContainer.ClassData classFromJson(JsonReader reader, @FromJson MappingDataContainer.FieldData fieldFromJson(JsonReader reader, - JsonAdapter> stringListAdapter) throws IOException { + JsonAdapter> stringListAdapter, + JsonAdapter constantDataAdapter) throws IOException { String name = null; String descriptor = null; List javadoc = null; + MappingDataContainer.ConstantData constant = null; reader.beginObject(); while (reader.hasNext()) { @@ -270,6 +303,9 @@ MappingDataContainer.FieldData fieldFromJson(JsonReader reader, case "javadoc": javadoc = stringListAdapter.fromJson(reader); break; + case "constant": + constant = constantDataAdapter.fromJson(reader); + break; default: reader.skipName(); break; @@ -281,7 +317,7 @@ MappingDataContainer.FieldData fieldFromJson(JsonReader reader, if (descriptor == null) throw new IllegalArgumentException("Field descriptor must not be null"); if (javadoc == null) javadoc = Collections.emptyList(); - return new ImmutableMappingDataContainer.ImmutableFieldData(name, descriptor, javadoc); + return new ImmutableMappingDataContainer.ImmutableFieldData(name, descriptor, javadoc, constant); } @FromJson @@ -325,11 +361,13 @@ MappingDataContainer.MethodData methodFromJson(JsonReader reader, } @FromJson - MappingDataContainer.ParameterData paramToJson(JsonReader reader) throws IOException { + MappingDataContainer.ParameterData paramFromJson(JsonReader reader, + JsonAdapter constantDataAdapter) throws IOException { byte index = -1; String name = null; String javadoc = null; + MappingDataContainer.ConstantData constant = null; reader.beginObject(); while (reader.hasNext()) { @@ -344,6 +382,9 @@ MappingDataContainer.ParameterData paramToJson(JsonReader reader) throws IOExcep case "javadoc": javadoc = reader.nextString(); break; + case "constant": + constant = constantDataAdapter.fromJson(reader); + break; default: reader.skipName(); break; @@ -353,6 +394,64 @@ MappingDataContainer.ParameterData paramToJson(JsonReader reader) throws IOExcep if (index < 0) throw new IllegalArgumentException("Parameter index must be present and positive"); - return new ImmutableMappingDataContainer.ImmutableParameterData(index, name, javadoc); + return new ImmutableMappingDataContainer.ImmutableParameterData(index, name, javadoc, constant); + } + + @FromJson + MappingDataContainer.ConstantData constantFromJson(JsonReader reader, + JsonAdapter constantTypeAdapter, + JsonAdapter> constantValuesAdapter) throws IOException { + MappingDataContainer.ConstantType type = null; + Collection values = null; + + reader.beginObject(); + while(reader.hasNext()) { + String propertyName = reader.nextName(); + switch (propertyName) { + case "type": + type = constantTypeAdapter.fromJson(reader); + break; + case "values": + values = constantValuesAdapter.fromJson(reader); + break; + default: + reader.skipName(); + break; + } + } + reader.endObject(); + + if (type == null) throw new IllegalArgumentException("Constant type must not be null"); + if (values == null) values = Collections.emptyList(); + + return new ImmutableMappingDataContainer.ImmutableConstantData(type, new ArrayList<>(values)); + } + + @FromJson + MappingDataContainer.ConstantValueData constantValueFromJson(JsonReader reader) throws IOException { + Integer value = null; + String reference = null; + + reader.beginObject(); + while (reader.hasNext()) { + String propertyName = reader.nextName(); + switch (propertyName) { + case "value": + value = reader.nextInt(); + break; + case "reference": + reference = reader.nextString(); + break; + default: + reader.skipName(); + break; + } + } + reader.endObject(); + + if (value == null) throw new IllegalArgumentException("Constant value must not be null"); + if (reference == null) throw new IllegalArgumentException("Constant reference must not be null"); + + return new ImmutableMappingDataContainer.ImmutableConstantValueData(value, reference); } }