it.auties.protobuf.serialization.model.object.ProtobufObjectElement Maven / Gradle / Ivy
package it.auties.protobuf.serialization.model.object;
import it.auties.protobuf.annotation.*;
import it.auties.protobuf.serialization.model.property.ProtobufPropertyElement;
import it.auties.protobuf.serialization.model.property.ProtobufPropertyType;
import javax.lang.model.element.*;
import java.util.*;
public class ProtobufObjectElement {
private final TypeElement typeElement;
private final Map properties;
private final List builders;
private final Map constants;
private final ProtobufEnumMetadata enumMetadata;
private final ExecutableElement deserializer;
private final Set reservedNames;
private final Set extends ReservedIndex> reservedIndexes;
private ProtobufUnknownFieldsElement unknownFieldsElement;
private final boolean group;
public ProtobufObjectElement(TypeElement typeElement, ProtobufEnumMetadata enumMetadata, ExecutableElement deserializer, boolean group) {
this.typeElement = typeElement;
this.enumMetadata = enumMetadata;
this.deserializer = deserializer;
this.reservedNames = getReservedNames();
this.reservedIndexes = getReservedIndexes();
this.builders = new ArrayList<>();
this.properties = new LinkedHashMap<>();
this.constants = new LinkedHashMap<>();
this.group = group;
}
private Set getReservedNames() {
if(enumMetadata != null) {
var enumeration = typeElement.getAnnotation(ProtobufEnum.class);
return enumeration == null ? Set.of() : Set.of(enumeration.reservedNames());
}
if(group) {
var group = typeElement.getAnnotation(ProtobufGroup.class);
return group == null ? Set.of() : Set.of(group.reservedNames());
}
var message = typeElement.getAnnotation(ProtobufMessage.class);
return message == null ? Set.of() : Set.of(message.reservedNames());
}
private Set getReservedIndexes() {
if(enumMetadata != null) {
var enumeration = typeElement.getAnnotation(ProtobufEnum.class);
if (enumeration == null) {
return Set.of();
}
return getReservedIndexes(enumeration.reservedIndexes(), enumeration.reservedRanges());
}
if(group) {
var group = typeElement.getAnnotation(ProtobufGroup.class);
if (group == null) {
return Set.of();
}
return getReservedIndexes(group.reservedIndexes(), group.reservedRanges());
}
var message = typeElement.getAnnotation(ProtobufMessage.class);
if (message == null) {
return Set.of();
}
return getReservedIndexes(message.reservedIndexes(), message.reservedRanges());
}
private Set getReservedIndexes(int[] indexes, ProtobufReservedRange[] ranges) {
var results = new HashSet();
for(var index : indexes) {
results.add(new ReservedIndex.Value(index));
}
for(var range : ranges) {
results.add(new ReservedIndex.Range(range.min(), range.max()));
}
return results;
}
public TypeElement element() {
return typeElement;
}
public Optional enumMetadata() {
return Optional.of(enumMetadata);
}
public List properties() {
return List.copyOf(properties.values());
}
public boolean isEnum() {
return typeElement.getKind() == ElementKind.ENUM;
}
public Map constants() {
return Collections.unmodifiableMap(constants);
}
public Optional addConstant(int fieldIndex, String fieldName) {
return Optional.ofNullable(constants.put(fieldIndex, fieldName));
}
public Optional addProperty(Element element, Element accessor, ProtobufPropertyType type, ProtobufProperty property) {
var fieldName = element.getSimpleName().toString();
var result = new ProtobufPropertyElement(fieldName, accessor, type, property, element instanceof ExecutableElement);
return Optional.ofNullable(properties.put(property.index(), result));
}
public void addBuilder(String className, List extends VariableElement> parameters, ExecutableElement executableElement) {
var builderElement = new ProtobufBuilderElement(className, parameters, executableElement);
builders.add(builderElement);
}
public List builders() {
return Collections.unmodifiableList(builders);
}
public Optional deserializer() {
return Optional.ofNullable(deserializer);
}
public Optional unknownFieldsElement() {
return Optional.ofNullable(unknownFieldsElement);
}
public void setUnknownFieldsElement(ProtobufUnknownFieldsElement unknownFieldsElement) {
this.unknownFieldsElement = unknownFieldsElement;
}
public boolean isGroup() {
return group;
}
public Set reservedNames() {
return reservedNames;
}
public boolean isNameDisallowed(String name) {
return reservedNames.contains(name);
}
public Set extends ReservedIndex> reservedIndexes() {
return reservedIndexes;
}
public boolean isIndexDisallowed(int index) {
return !reservedIndexes.stream()
.allMatch(entry -> entry.isAllowed(index));
}
public sealed interface ReservedIndex {
boolean isAllowed(int index);
record Range(int min, int max) implements ReservedIndex {
@Override
public boolean isAllowed(int index) {
return index < min || index > max;
}
}
record Value(int value) implements ReservedIndex {
@Override
public boolean isAllowed(int index) {
return index != value;
}
}
}
}