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

org.eclipse.jnosql.mapping.reflection.ClassGraphClassScanner Maven / Gradle / Ivy

/*
 *  Copyright (c) 2023, 2024 Contributors to the Eclipse Foundation
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *   The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 *   and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
 *
 *   You may elect to redistribute this code under either of these licenses.
 *
 *   Contributors:
 *
 *   Otavio Santana
 */
package org.eclipse.jnosql.mapping.reflection;

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import jakarta.data.repository.BasicRepository;
import jakarta.data.repository.CrudRepository;
import jakarta.data.repository.DataRepository;
import jakarta.data.repository.Repository;
import jakarta.nosql.Entity;
import jakarta.nosql.Embeddable;
import org.eclipse.jnosql.mapping.NoSQLRepository;
import org.eclipse.jnosql.mapping.metadata.ClassScanner;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import static java.util.Collections.unmodifiableSet;
import static java.util.stream.Collectors.toUnmodifiableSet;

/**
 * Scanner classes that will load entities with both Entity and Embeddable
 * annotations and repositories: interfaces that extend DataRepository
 * and has the Repository annotation.
 */
enum ClassGraphClassScanner implements ClassScanner {

    INSTANCE;

    private final Set> entities;
    private final Set> repositories;
    private final Set> embeddables;


    ClassGraphClassScanner() {
        entities = new HashSet<>();
        embeddables = new HashSet<>();
        repositories = new HashSet<>();

        Logger logger = Logger.getLogger(ClassGraphClassScanner.class.getName());
        logger.fine("Starting scan class to find entities, embeddable and repositories.");
        try (ScanResult result = new ClassGraph().enableAllInfo().scan()) {
            checkInvalidRepositories(loadInvalidRepositories(result));
            this.entities.addAll(loadEntities(result));
            this.embeddables.addAll(loadEmbeddable(result));
            this.repositories.addAll(loadRepositories(result));
        }
        logger.fine(String.format("Finished the class scan with entities %d, embeddables %d and repositories: %d"
                , entities.size(), embeddables.size(), repositories.size()));

    }


    @Override
    public Set> entities() {
        return unmodifiableSet(entities);
    }

  @Override
    public Set> repositories() {
        return unmodifiableSet(repositories);
    }


   @Override
    public Set> embeddables() {
        return unmodifiableSet(embeddables);
    }

    @Override
    public > Set> repositories(Class filter) {
        Objects.requireNonNull(filter, "filter is required");
        return repositories.stream().filter(filter::isAssignableFrom)
                .filter(c -> Arrays.asList(c.getInterfaces()).contains(filter))
                .collect(toUnmodifiableSet());
    }


    @Override
    public Set> repositoriesStandard() {
        return repositories.stream()
                .filter(c -> {
                    List> interfaces = Arrays.asList(c.getInterfaces());
                    return interfaces.contains(CrudRepository.class)
                            || interfaces.contains(BasicRepository.class)
                            || interfaces.contains(NoSQLRepository.class)
                            || interfaces.contains(DataRepository.class);
                }).collect(Collectors.toUnmodifiableSet());
    }


    @SuppressWarnings("rawtypes")
    private static List> loadRepositories(ScanResult scan) {
        return scan.getClassesWithAnnotation(Repository.class)
                .getInterfaces()
                .loadClasses(DataRepository.class)
                .stream().filter(RepositoryFilter.INSTANCE)
                .toList();
    }

    @SuppressWarnings("rawtypes")
    private static void checkInvalidRepositories(List> classes) {
        if (!classes.isEmpty()) {
            Logger logger = Logger.getLogger(ClassGraphClassScanner.class.getName());
            String repositories = classes.stream()
                    .map(Class::getName)
                    .collect(Collectors.joining(","));
            logger.info("The following repositories cannot be implemented by the Jakarta Data Provider JNoSQL " +
                "because the entities do not have the " + jakarta.nosql.Entity.class.getName() + " annotation: " +
                repositories);
        }
    }


    @SuppressWarnings("rawtypes")
    private static List> loadInvalidRepositories(ScanResult scan) {
        return scan.getClassesWithAnnotation(Repository.class)
                .getInterfaces()
                .loadClasses(DataRepository.class)
                .stream().filter(RepositoryFilter.INSTANCE::isInvalid)
                .toList();
    }

    private static List> loadEmbeddable(ScanResult scan) {
        return scan.getClassesWithAnnotation(Embeddable.class).loadClasses();
    }

    private static List> loadEntities(ScanResult scan) {
        return scan.getClassesWithAnnotation(Entity.class).loadClasses();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy