ProjectAres/API/api/src/main/java/tc/oc/api/document/DocumentMeta.java

102 lines
3.5 KiB
Java

package tc.oc.api.document;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import tc.oc.api.annotations.Serialize;
import tc.oc.api.docs.virtual.Document;
/**
* Meta-info about a {@link Document} subtype, including all property {@link Accessor}s.
*/
public class DocumentMeta<T extends Document> {
private final Class<T> type;
private final ImmutableList<DocumentMeta<? super T>> ancestors;
private final Class<? extends Document> baseType;
private final ImmutableMap<String, Getter> getters;
private final ImmutableMap<String, Setter> setters;
public DocumentMeta(Class<T> type, List<DocumentMeta<? super T>> ancestors, Class<? extends Document> baseType, Map<String, Getter> getters, Map<String, Setter> setters) {
this.type = type;
this.ancestors = ImmutableList.copyOf(Iterables.concat(Collections.singleton(this), ancestors));
this.baseType = baseType;
this.getters = ImmutableMap.copyOf(getters);
this.setters = ImmutableMap.copyOf(setters);
}
@Override
public String toString() {
return getClass().getSimpleName() + "<" + type() + ">";
}
/**
* The {@link Document} subtype described by this metadata
*/
public Class<T> type() {
return type;
}
/**
* All ancestor {@link Document}s of this document, in resolution order.
* This list includes every supertype of this document that is also a subtype
* of {@link Document}, including this document itself.
*
* This list can include both classes and interfaces, which are flattened into
* a single list using the C3 linearization algorithm. Classes always come before
* interfaces in the list.
*/
public ImmutableList<DocumentMeta<? super T>> ancestors() {
return ancestors;
}
/**
* Best concrete base class to extend when implementing this document
* (used by the document generator)
*/
public Class<? extends Document> baseType() {
return baseType;
}
/**
* All property getters visible on this document type,
* including inherited getters that are not overridden.
*/
public ImmutableMap<String, Getter> getters() {
return getters;
}
/**
* All property setters visible on this document type,
* including inherited setters that are not overridden.
*/
public ImmutableMap<String, Setter> setters() {
return setters;
}
private static boolean isSerialized(AnnotatedElement element, boolean def) {
final Serialize annotation = element.getAnnotation(Serialize.class);
return annotation != null ? annotation.value() : def;
}
public static <T extends AnnotatedElement> Iterable<T> serializedMembers(Class<? extends Document> type, Iterable<T> members) {
final boolean def = isSerialized(type, false);
return Iterables.filter(members, member -> isSerialized(member, def));
}
public static Iterable<Method> serializedMethods(Class<? extends Document> type) {
return serializedMembers(type, Arrays.asList(type.getDeclaredMethods()));
}
public static Iterable<Field> serializedFields(Class<? extends Document> type) {
return serializedMembers(type, Arrays.asList(type.getDeclaredFields()));
}
}