ProtocolLib/src/main/java/com/comphenix/protocol/error/ReportType.java

148 lines
5.1 KiB
Java

package com.comphenix.protocol.error;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a strongly-typed report. Subclasses should be immutable.
* <p>
* By convention, a report must be declared as a static field publicly accessible from the sender class.
* @author Kristian
*/
public class ReportType {
private final String errorFormat;
// Used to store the report name
protected String reportName;
/**
* Construct a new report type.
* @param errorFormat - string used to format the underlying report.
*/
public ReportType(String errorFormat) {
this.errorFormat = errorFormat;
}
/**
* Convert the given report to a string, using the provided parameters.
* @param parameters - parameters to insert, or NULL to insert nothing.
* @return The full report in string format.
*/
public String getMessage(Object[] parameters) {
if (parameters == null || parameters.length == 0)
return toString();
else
return String.format(errorFormat, parameters);
}
@Override
public String toString() {
return errorFormat;
}
/**
* Retrieve the class of the given sender.
* <p>
* If the sender is already a Class, we return it.
* @param sender - the sender to look up.
* @return The class of the sender.
*/
public static Class<?> getSenderClass(Object sender) {
if (sender == null)
throw new IllegalArgumentException("sender cannot be null.");
else if (sender instanceof Class<?>)
return (Class<?>) sender;
else
return sender.getClass();
}
/**
* Retrieve the full canonical name of a given report type.
* <p>
* Note that the sender may be a class (for static callers), in which
* case it will be used directly instead of its getClass() method.
* <p>
* It is thus not advisable for class classes to report reports.
* @param sender - the sender, or its class.
* @param type - the report type.
* @return The full canonical name.
*/
public static String getReportName(Object sender, ReportType type) {
if (sender == null)
throw new IllegalArgumentException("sender cannot be null.");
return getReportName(getSenderClass(sender), type);
}
/**
* Retrieve the full canonical name of a given report type.
* <p>
* This is in the format <i>canonical_name_of_class#report_type</i>
* @param sender - the sender class.
* @param type - the report instance.
* @return The full canonical name.
*/
private static String getReportName(Class<?> sender, ReportType type) {
if (sender == null)
throw new IllegalArgumentException("sender cannot be null.");
// Whether or not we need to retrieve the report name again
if (type.reportName == null) {
for (Field field : getReportFields(sender)) {
try {
field.setAccessible(true);
if (field.get(null) == type) {
// We got the right field!
return type.reportName = field.getDeclaringClass().getCanonicalName() + "#" + field.getName();
}
} catch (IllegalAccessException e) {
throw new FieldAccessException("Unable to read field " + field, e);
}
}
throw new IllegalArgumentException("Cannot find report name for " + type);
}
return type.reportName;
}
/**
* Retrieve all publicly associated reports.
* @param sender - sender class.
* @return All associated reports.
*/
public static ReportType[] getReports(Class<?> sender) {
if (sender == null)
throw new IllegalArgumentException("sender cannot be NULL.");
List<ReportType> result = new ArrayList<>();
// Go through all the fields
for (Field field : getReportFields(sender)) {
try {
field.setAccessible(true);
result.add((ReportType) field.get(null));
} catch (IllegalAccessException e) {
throw new FieldAccessException("Unable to read field " + field, e);
}
}
return result.toArray(new ReportType[0]);
}
/**
* Retrieve all publicly associated report fields.
* @param clazz - sender class.
* @return All associated report fields.
*/
private static List<Field> getReportFields(Class<?> clazz) {
return FuzzyReflection.fromClass(clazz, true)
.getFieldList(FuzzyFieldContract.newBuilder()
.requireModifier(Modifier.STATIC)
.typeDerivedOf(ReportType.class)
.build());
}
}