package org.springframework.data.repository.config;
import java.beans.Introspector;
import java.io.IOException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.util.Streamable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
class DefaultImplementationLookupConfiguration implements ImplementationLookupConfiguration {
private final ImplementationDetectionConfiguration config;
private final String interfaceName;
private final String beanName;
DefaultImplementationLookupConfiguration(ImplementationDetectionConfiguration config, String interfaceName) {
Assert.notNull(config, "ImplementationDetectionConfiguration must not be null!");
Assert.hasText(interfaceName, "Interface name must not be null or empty!");
this.config = config;
this.interfaceName = interfaceName;
this.beanName = Introspector
.decapitalize(ClassUtils.getShortName(interfaceName).concat(config.getImplementationPostfix()));
}
@Override
public String getImplementationBeanName() {
return beanName;
}
@Override
public String getImplementationPostfix() {
return config.getImplementationPostfix();
}
@Override
public Streamable<TypeFilter> getExcludeFilters() {
return config.getExcludeFilters().and(new AnnotationTypeFilter(NoRepositoryBean.class));
}
@Override
public MetadataReaderFactory getMetadataReaderFactory() {
return config.getMetadataReaderFactory();
}
@Override
public Streamable<String> getBasePackages() {
return Streamable.of(ClassUtils.getPackageName(interfaceName));
}
@Override
public String getImplementationClassName() {
return ClassUtils.getShortName(interfaceName).concat(getImplementationPostfix());
}
@Override
public boolean hasMatchingBeanName(BeanDefinition definition) {
Assert.notNull(definition, "BeanDefinition must not be null!");
return beanName != null && beanName.equals(config.generateBeanName(definition));
}
@Override
public boolean matches(BeanDefinition definition) {
Assert.notNull(definition, "BeanDefinition must not be null!");
String beanClassName = definition.getBeanClassName();
if (beanClassName == null || isExcluded(beanClassName, getExcludeFilters())) {
return false;
}
String beanPackage = ClassUtils.getPackageName(beanClassName);
String shortName = ClassUtils.getShortName(beanClassName);
String localName = shortName.substring(shortName.lastIndexOf('.') + 1);
return localName.equals(getImplementationClassName())
&& getBasePackages().stream().anyMatch(it -> beanPackage.startsWith(it));
}
private boolean isExcluded(String beanClassName, Streamable<TypeFilter> filters) {
try {
MetadataReader reader = getMetadataReaderFactory().getMetadataReader(beanClassName);
return filters.stream().anyMatch(it -> matches(it, reader));
} catch (IOException o_O) {
return true;
}
}
private boolean matches(TypeFilter filter, MetadataReader reader) {
try {
return filter.match(reader, getMetadataReaderFactory());
} catch (IOException e) {
return false;
}
}
}