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

ai.timefold.jpyinterpreter.AnnotationMetadata Maven / Gradle / Ivy

Go to download

Timefold solves planning problems. This lightweight, embeddable planning engine implements powerful and scalable algorithms to optimize business resource scheduling and planning. This module contains the Python interpreter.

The newest version!
package ai.timefold.jpyinterpreter;

import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

public record AnnotationMetadata(@NonNull Class annotationType,
        @NonNull Map annotationValueMap,
        @Nullable Class fieldTypeOverride) {
    public void addAnnotationTo(ClassVisitor classVisitor) {
        visitAnnotation(classVisitor.visitAnnotation(Type.getDescriptor(annotationType), true));
    }

    public void addAnnotationTo(FieldVisitor fieldVisitor) {
        visitAnnotation(fieldVisitor.visitAnnotation(Type.getDescriptor(annotationType), true));
    }

    public void addAnnotationTo(MethodVisitor methodVisitor) {
        visitAnnotation(methodVisitor.visitAnnotation(Type.getDescriptor(annotationType), true));
    }

    public static List getAnnotationListWithoutRepeatable(List metadata) {
        List out = new ArrayList<>();
        Map, List> repeatableAnnotationMap = new LinkedHashMap<>();
        Map, Class> fieldTypeOverrideMap = new LinkedHashMap<>();
        for (AnnotationMetadata annotation : metadata) {
            Repeatable repeatable = annotation.annotationType().getAnnotation(Repeatable.class);
            if (repeatable == null) {
                out.add(annotation);
                continue;
            }
            var annotationContainer = repeatable.value();
            fieldTypeOverrideMap.put(annotationContainer, annotation.fieldTypeOverride());
            repeatableAnnotationMap.computeIfAbsent(annotationContainer,
                    ignored -> new ArrayList<>()).add(annotation);
        }
        for (var entry : repeatableAnnotationMap.entrySet()) {
            out.add(new AnnotationMetadata(entry.getKey(),
                    Map.of("value", entry.getValue().toArray(AnnotationMetadata[]::new)),
                    fieldTypeOverrideMap.get(entry.getKey())));
        }
        return out;
    }

    public static Type getValueAsType(String className) {
        return Type.getType("L" + className.replace('.', '/') + ";");
    }

    private void visitAnnotation(AnnotationVisitor annotationVisitor) {
        for (var entry : annotationValueMap.entrySet()) {
            var annotationAttributeName = entry.getKey();
            var annotationAttributeValue = entry.getValue();

            visitAnnotationAttribute(annotationVisitor, annotationAttributeName, annotationAttributeValue);
        }
        annotationVisitor.visitEnd();
    }

    private void visitAnnotationAttribute(AnnotationVisitor annotationVisitor, String attributeName, Object attributeValue) {
        if (attributeValue instanceof Number
                || attributeValue instanceof Boolean
                || attributeValue instanceof Character
                || attributeValue instanceof String) {
            annotationVisitor.visit(attributeName, attributeValue);
            return;
        }

        if (attributeValue instanceof Type type) {
            annotationVisitor.visit(attributeName, type);
            return;
        }

        if (attributeValue instanceof AnnotationMetadata annotationMetadata) {
            annotationMetadata.visitAnnotation(
                    annotationVisitor.visitAnnotation(attributeName, Type.getDescriptor(annotationMetadata.annotationType)));
            return;
        }

        if (attributeValue instanceof Enum enumValue) {
            annotationVisitor.visitEnum(attributeName, Type.getDescriptor(enumValue.getClass()),
                    enumValue.name());
            return;
        }

        if (attributeValue.getClass().isArray()) {
            var arrayAnnotationVisitor = annotationVisitor.visitArray(attributeName);
            var arrayLength = Array.getLength(attributeValue);
            for (int i = 0; i < arrayLength; i++) {
                visitAnnotationAttribute(arrayAnnotationVisitor, attributeName, Array.get(attributeValue, i));
            }
            arrayAnnotationVisitor.visitEnd();
            return;
        }
        throw new IllegalArgumentException("Annotation of type %s has an illegal value %s for attribute %s."
                .formatted(annotationType, attributeValue, attributeName));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy