Skip to content

Instantly share code, notes, and snippets.

@blvp
Last active August 15, 2016 21:10
Show Gist options
  • Select an option

  • Save blvp/1ffc99886d96f3ddea2f to your computer and use it in GitHub Desktop.

Select an option

Save blvp/1ffc99886d96f3ddea2f to your computer and use it in GitHub Desktop.
checks that method has at least one string argument, that should be first
package ru.dz.tele2.wsc.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static ru.dz.tele2.wsc.commons.util.LambdaUtil.not;
@Slf4j
public class ServiceLayerMethodParameterCheckPostProcessor implements BeanDefinitionRegistryPostProcessor {
private String basePackage;
private List<String> packagesToScan;
private Predicate<Class<?>> inPackageList = clazz ->
this.packagesToScan.stream()
.map(clazz.getPackage().getName()::equals)
.reduce((a, b) -> a || b)
.orElse(false);
public ServiceLayerMethodParameterCheckPostProcessor(String basePackage, List<String> packagesToScan) {
this.basePackage = basePackage;
this.packagesToScan = packagesToScan;
}
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public void setPackagesToScan(List<String> packagesToScan) {
this.packagesToScan = packagesToScan;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
new ClassPathScanningCandidateComponentProvider(true)
.findCandidateComponents(basePackage).stream()
.map(beanDefinition -> {
try {
return Class.forName(beanDefinition.getBeanClassName());
} catch (ClassNotFoundException e) {
log.error(e.getMessage());
return null;
}
})
.filter(Objects::nonNull)
.filter(not(Class::isMemberClass))
.map(Class::getInterfaces)
.flatMap(Stream::of)
.filter(inPackageList)
.map(Class::getDeclaredMethods)
.flatMap(Stream::of)
.filter(method -> Modifier.isPublic(method.getModifiers()))
.filter(method -> !Modifier.isStatic(method.getModifiers()))
.filter(method -> method.getParameterCount() == 0
|| !method.getParameterTypes()[0].equals(String.class)
)
.map(Method::toGenericString)
.reduce((a, b) -> a + ", " + b)
.ifPresent(message -> {
throw new BeanCreationException(
"Bad service layer setup " +
"all methods [ " + message + " ] " +
"should have at least one string argument aka msisdn"
);
});
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
@saladinkzn
Copy link
Copy Markdown

форич неочевидный
.filter(m -> condition(m))
.findFirst()
.ifPresent(() -> throw new createEx(m));

@blvp
Copy link
Copy Markdown
Author

blvp commented Feb 26, 2016

Соглашусь, изначально закладывался сбор всех таких методов и их вывод в одном сообщении списком.

@xak2000
Copy link
Copy Markdown

xak2000 commented Aug 15, 2016

    private Predicate<Class<?>> inPackageList = clazz ->
            this.packagesToScan.stream()
                    .map(clazz.getPackage().getName()::equals)
                    .reduce((a, b) -> a || b)
                    .orElse(false);

можно заменить на более эффективную (скорее всего :)) конструкцию:

    private Predicate<Class<?>> inPackageList = clazz -> packagesToScan.contains(clazz.getPackage().getName());

т.к. этот предикат будет пересчитываться для каждого сканируемого класса. Да и просто короче. :) Можно даже заинлайнить.

А если сильно хочется стримов :), то можно сделать так:

    private Predicate<Class<?>> inPackageList = clazz ->
            this.packagesToScan.stream()
                    .filter(clazz.getPackage().getName()::equals)
                    .findAny() // short-circuiting terminal operation - faster than reduce
                    .isPresent();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment