How to get entityName or interface name in SpEL for generic repositories in PreAuthorize - spring

I'd like to create a generic security crud repository and annotate each method with preauthorize, however I cannot get how to retrieve entity class name
#NoRepositoryBean
public interface AbstractEntityRepository<T extends AbstractEntity> extends CrudRepository<T, String> {
#Override
#PreAuthorize("hasPermission(null, #entityName, 'find');
Iterable<T> findAll();
}
public interface UserRepository extends AbstractEntityRepository<User> {}
in this case, entityName is always null.
#Component
#Log
public class CustomPermissionEvaluator implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission)
log.fine("type " + targetType); // <- null
return true;
}
...
Any idea how to get either "User" or "UserRepository" ?

#Component
public class ClassTypeResolver {
public static String resolve(Object object) {
if (AopUtils.isJdkDynamicProxy(object)) {
try {
return ((SimpleJpaRepository) ((Advised)object).getTargetSource().getTarget()).getDomainClass().getCanonicalName();
} catch (Exception e) {
return null;
}
} else {
return ((SimpleJpaRepository) object).getDomainClass().getCanonicalName();
}
}
}

Related

How to use Conditional interface in spring boot with value inside a list

I have application-sample.YAML file where I have data. After loading the data, based on certain fields. I want to decide which few components to load or not to load. I can see this below condition class loads first, as a result, I am getting the data null because this condition class is loading first before my Data loaded.
#Configuration
public class AwsCondition implements Condition {
#Autowired
MyTestData data;
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO Auto-generated method stub
log.info("inside...........condition");
if(data.getListeners().size()>1){
return true;
}
return false;
}
}
MyTestData.java
#Slf4j
#Data
#ConfigurationProperties
#Component
public class MyTestData implements InitializingBean {
List<Listener> listeners = new ArrayList<>();
#Data
public static class Listener {
private String type;
private String name;
}
#Override
public void afterPropertiesSet() throws Exception {
if (this.getListeners().isEmpty()) {
log.info("Nothing configured. Please verify application-test.yml is configured properly.");
System.exit(1);
}
}
}
ConditionTest class
#Component
#Conditional(AwsCondition.class)
public class TestS3ListenerRouter extends RouteBuilder {
//My all logic lying here
}
Try the following:
#Component
public class AwsCondition implements Condition {
#Autowired
MyTestData data;
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO Auto-generated method stub
log.info("inside...........condition");
if(data.getListeners().size()>1){
return true;
}
return false;
}
}

How to autowire an Inteface which extends JpaRepository in an another class

#Repository
public interface Userrepo extends JpaRepository<Users, String> {
}
I want the above interface to be autowired in the below class
#Component
public class Userauth {
#Autowired
Userrepo urepo;
public boolean check(String name,String password) {
Application a=new Application();
Optional<Users> u=urepo.findById(name);
if(!u.isEmpty()) {
Users ud=u.get();
if(ud.getPassword().equals(password))
return true;
}
return false;
}
}
but its giving an error "urepo" is null
in the log getting this.
Ignored because not a concrete top-level class: file [C:\Users\Documents\workspace-spring-tool-suite-4-4.9.0.RELEASE\1Sampleproject\target\classes\com\example\demo\repos\Userrepo.class]

Hibernate validation - autowired returns null

After looking around, I couldn't find any good solution to this.
My autowired didn't work as expected where it returns null. I've autowired this particular class in other classes and it works so it only doesn't work in constraintvalidator classes.
UserService class
#Service
public class UserService {
#Autowired
private UserRepository userRep;
public void addUser(User user) {
userRep.save(user);
}
public void deleteUser(long userId) {
userRep.deleteById(userId);
}
public List<User> retrieveAllUsers(){
Iterable<User>temp =userRep.findAll();
List<User>allUsers = null;
temp.forEach(allUsers::add);
return allUsers;
}
public boolean searchByEmail(String email) {
return userRep.findByEmail(email);
}
public void updateUser(User user) {
userRep.save(user);
}
}
Annotation interface class
#Target(ElementType.FIELD)
//When will the annotation be processed compilation, runtime etc
#Retention(RetentionPolicy.RUNTIME)
//Where is the logic
#Constraint(validatedBy = EmailValidator.class)
#Documented
public #interface ValidEmail {
//Error message
String message() default "Invalid email";
//Required for annotation
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Annotation logic class. The autowired here returns null
public class EmailValidator implements ConstraintValidator<ValidEmail, String> {
#Autowired
private UserService service;
//Actual place to place the logic to check if the data is valid or not
#Override
public boolean isValid(String email, ConstraintValidatorContext context) {
if (email == null) {
return false;
}
List<User> users = service.retrieveAllUsers();
if (users.size() > 0) {
return Pattern.matches("(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])", email)
&& service.searchByEmail(email);
}
else {
return Pattern.matches("(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])", email);
}
}
#Override
public void initialize(ValidEmail validEmail) {
validEmail.message();
}
}
Main
#SpringBootApplication
#ComponentScan(basePackages = {
"com.Alex.Mains", "com.Alex.UserPackage", "com.Alex.Flights", "com.Alex.Security"
})
#EntityScan( basePackages = {"com.Alex.UserPackage", "com.Alex.Flights"})
#EnableJpaRepositories({"com.Alex.UserPackage", "com.Alex.Flights"})
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
// #Bean
// public Validator validator(final AutowireCapableBeanFactory beanFactory) {
//
// ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
// .configure()
// .constraintValidatorFactory(new SpringConstraintValidatorFactory(beanFactory))
// .buildValidatorFactory();
//
// return validatorFactory.getValidator();
// }
}
Edit: Tried #Componenet
Fixed with adding the following to application.properties. No idea why but it works
spring.jpa.properties.javax.persistence.validation.mode=none
EDIT: My Suggestion
Instead of a custom validator, use the existing #EMail and a unique constraint:
#Entity
public class User {
// ...your properties
#Email
#Column(unique = true)
private String email.
// Rest of class...
}
OLD:
So, first off:
List<User> users = service.retrieveAllUsers();
if (users.size() > 0) {
You are fetching all the Users from the database, just to check whether any users exists? This is very, very inefficient. If you are already using Spring Data, you can just do
#Query("SELECT COUNT(*) > 0 FROM Users")
boolean anyExists();
Furthermore, your Service does not get injected, because EmailValidator is a POJO (plain old java object) and not a Spring managed component. If you annotate it with #Component or #Service Spring will take care of injection.
But I would not recommend that. I'm not sure what your exact use case is, but validators are often used on Entities and as such, they get called when the entity is created or updated. You don't want to issue additional queries in those cases.
Like I said, I don't know what exactly you are trying to achieve, but you could use the existing #Email validator (you can even provide a custom regular expression with the regexp attribute).

How to ignore some parameter in JPA

I pass arguments to get data from database by JPA.
There are two arguments.
The first argument is ServiceType ; to switch database from Aspect (AOP)
The second argument is used to make query.
However there is org.springframework.data.jpa.repository.query.ParameterBinder.bind error
in conclusion, how to ignore the first(ServiceType) argument to make JPA query.
The code is like that.
#Repository
public interface BlogRepository extends JpaRepository<Blog, Integer> {
List<Blog> findByName(ServiceType serviceType, String name, Pageable pageable);
}
#Aspect
#Order(1)
#Component
public class MDBDecisionAspect {
private static ThreadLocal<ServiceType> localService = new ThreadLocal<>();
#Pointcut("execution(public * com.test.jpa.mdb..*.*(com.test.enums.ServiceType, ..))")
public void repositoryAspectTarget() {
}
#Around("repositoryAspectTarget()")
public Object initDaoService(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
if (args[0] != null && ServiceType.class.equals(args[0].getClass())) {
setServiceType(((ServiceType) args[0]));
}
return joinPoint.proceed();
}
#AfterReturning("repositoryAspectTarget()")
public void afterInitDaoServiceReturningTargetMethod() {
setServiceType(null);
}
public static ServiceType getServiceType() {
return localService.get();
}
public static void setServiceType(ServiceType serviceType) {
localService.set(serviceType);
}
}
create a service class and call repository in it. So you can use serviceType inside service class.
#Repository
public interface BlogRepository extends JpaRepository<Blog, Integer> {
List<Blog> findByName(String name, Pageable pageable);
}
class BlogService{
public List<Blog> getListOfBlog(ServiceType st, String name){
blogRepository. findByName(name);
}
}
change aspect pointcut to check service class.

Spring Boot & Data Repositories - fragment implementation x does not implement x

I upgraded from Spring Boot v.1.5.8 to v.2.1.5. When I try to start the application I get the following error:
IllegalArgumentException: Fragment implementation .OtmUniParentRepository2019GeneratedImpl$$EnhancerBySpringCGLIB$$cdf9e294 does not implement x.OtmUniParentRepository2019Generated!
Why I can't start it anymore?
The files:
OtoUniChildRepository2019
#RepositoryRestResource(collectionResourceRel = "OtoUniChild2019", path = "OtoUniChild2019")
public interface OtoUniChildRepository2019 extends OtoUniChildRepository2019Generated {
}
#Transactional
class OtoUniChildRepository2019Impl extends HeartcoreRepositoryImpl<OtoUniChild> {
#PostConstruct
private void setIni() {
super.setIni(OtoUniChild.TABLENAME, OtoUniChild.getColumnName(), OtoUniChild.class, "AGRIDB2019");
}
}
OtoUniChildRepository2019Generated
public interface OtoUniChildRepository2019Generated extends HeartcoreRepository<OtoUniChild> {
OtoUniChild findByIdAndOtoUniParentIsNotNull(#Param("id") String id);
OtoUniChild findByOtoUniParentId(#Param("id") String id);
}
#Transactional
class OtoUniChildRepository2019GeneratedImpl extends HeartcoreRepositoryImpl<OtoUniChild> {
#PostConstruct
private void setIni() {
super.setIni(OtoUniChild.TABLENAME, OtoUniChild.getColumnName(), OtoUniChild.class, "AGRIDB2019");
}
}
HeartcoreRepository
#NoRepositoryBean
public interface HeartcoreRepository<T extends Heartcore> extends RevisionRepository<T, String, Integer>, PagingAndSortingRepository<T, String>, HeartcoreCustomRepository<T> {
#Override
T findOne(String id);
boolean existsById(String id);
#Override
Collection<T> findAll();
List<T> findAllByKanton(#Param("kanton") String kanton);
}
HeartcoreCustomRepository
public interface HeartcoreCustomRepository<T extends Heartcore> {
List<T> findCustom(String sqlQuery);
List<T> findCustom(String select, String where);
Class<T> getType();
T findOne(String id);
Collection<T> findAll();
String getSequence(String sequenceName);
}
HeartcoreCustomRepositoryImpl
#Transactional
public class HeartcoreRepositoryImpl<T extends Heartcore> implements HeartcoreCustomRepository<T> {
#PersistenceContext
protected EntityManager entityManager;
// irrelevant code
public void setIni(String tablename, List<String> columns, Class<T> type, String schema) {
this.tablename = tablename;
this.columns = columns;
this.type = type;
this.schema = schema;
MultitenantDataSource multitenantDataSource = (MultitenantDataSource) entityManager.getEntityManagerFactory().getProperties().get("hibernate.connection.datasource");
DataSource dataSource = (DataSource) multitenantDataSource.determineTargetDataSource();
try {
this.dbDriver = dataSource.getConnection().getMetaData().getDriverName();
}
catch (SQLException e) {
e.printStackTrace();
}
}
// irrelevant code
With 1.5.8 it works fine and I couldn't find infos about breaking changes.
EDIT: Is something wrong with this inheritance structure of the repositories? I tried some different approaches but none worked. Is there an other way to implement some basic functionality for repositories?

Resources