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

117 lines
3.4 KiB
Java

package tc.oc.api.document;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Type;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.reflect.TypeToken;
import tc.oc.api.docs.virtual.Document;
import tc.oc.commons.core.reflect.Types;
import static com.google.common.base.Preconditions.checkNotNull;
public abstract class BaseAccessor<T> implements Accessor<T> {
private final DocumentRegistry registry;
private DocumentMeta<?> document;
private @Nullable Accessor<?> override;
protected BaseAccessor(DocumentRegistry registry) {
this.registry = checkNotNull(registry);
}
@Override
public DocumentMeta<?> document() {
if(document == null) {
this.document = registry.getMeta((Class<? extends Document>) member().getDeclaringClass());
Accessor<?> override = null;
for(DocumentMeta<?> ancestor : document.ancestors()) {
if(ancestor != document) {
override = getOverrideIn(ancestor);
if(override != null) break;
}
}
this.override = override;
}
return document;
}
@Override
public String name() {
return member().getName();
}
@Override
public Type resolvedType(Type documentType) {
return resolvedType(TypeToken.of(documentType));
}
@Override
public Type resolvedType(TypeToken documentType) {
return documentType.resolveType(type()).getType();
}
@Override
public @Nullable Accessor<?> override() {
document();
return override;
}
protected abstract @Nullable Accessor<?> getOverrideIn(DocumentMeta<?> ancestor);
@Override
public boolean isPrimitive() {
final Type type = type();
return type instanceof Class && ((Class) type).isPrimitive();
}
@Override public Class<T> boxType() {
return isPrimitive() ? Types.box(rawType())
: rawType();
}
@Override
public boolean isNullable() {
if(isPrimitive()) return false;
{
final AccessibleObject member = member();
if(member.getAnnotation(Nullable.class) != null) return true;
if(member.getAnnotation(Nonnull.class) != null) return false;
}
{
final Member member = member();
if(member.getDeclaringClass().getAnnotation(Nullable.class) != null) return true;
if(member.getDeclaringClass().getAnnotation(Nonnull.class) != null) return false;
}
if(override() != null) return override().isNullable();
return true;
}
@Override
public boolean hasDefault() {
return isNullable() || isImplemented(document().type()) || isImplemented(document().baseType());
}
@Override
public T validate(T value) {
if(value == null) {
if(!isNullable()) {
throw new NullPointerException("null value for non-nullable property " + name());
}
} else {
if(!boxType().isInstance(value)) {
throw new ClassCastException("value of type " + value.getClass().getName() +
" is not assignable to property " + name() + " of type " + rawType().getName());
}
}
return value;
}
}