All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 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 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 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;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy