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