diff --git a/hello-jpa-repository/src/main/java/com/bobocode/config/JpaConfig.java b/hello-jpa-repository/src/main/java/com/bobocode/config/JpaConfig.java index ec3d6a4..717d3fe 100644 --- a/hello-jpa-repository/src/main/java/com/bobocode/config/JpaConfig.java +++ b/hello-jpa-repository/src/main/java/com/bobocode/config/JpaConfig.java @@ -1,9 +1,14 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.Database; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import javax.sql.DataSource; @@ -17,24 +22,36 @@ * todo: 3. Configure {@link javax.persistence.EntityManagerFactory} bean with name "entityManagerFactory" * todo: 4. Enable JPA repository, set appropriate package using annotation property "basePackages" */ +@Configuration +@EnableJpaRepositories(basePackages = "com.bobocode.dao") public class JpaConfig { + @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } + @Bean public JpaVendorAdapter jpaVendorAdapter() { // todo: create HibernateJpaVendorAdapter + HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); // todo: set H2 database + adapter.setDatabase(Database.H2); // todo: enable DDL generation - throw new UnsupportedOperationException("Application won't start until you provide configs"); + adapter.setGenerateDdl(true); + return adapter; } - public LocalContainerEntityManagerFactoryBean localContainerEMF() { + @Bean("entityManagerFactory") + public LocalContainerEntityManagerFactoryBean localContainerEMF(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) { // todo: create and configure required bean + LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); + emf.setDataSource(dataSource); + emf.setJpaVendorAdapter(jpaVendorAdapter); // todo: set package "com.bobocode.model" to scan for JPA entities - throw new UnsupportedOperationException("Application won't start until you provide configs"); + emf.setPackagesToScan("com.bobocode.model");// JPA entity classes will be loaded from this package + return emf; } } diff --git a/hello-jpa-repository/src/main/java/com/bobocode/config/RootConfig.java b/hello-jpa-repository/src/main/java/com/bobocode/config/RootConfig.java index 58293dd..1e57517 100644 --- a/hello-jpa-repository/src/main/java/com/bobocode/config/RootConfig.java +++ b/hello-jpa-repository/src/main/java/com/bobocode/config/RootConfig.java @@ -1,6 +1,13 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; /** * This class is provides root Java config for Spring application. @@ -10,6 +17,14 @@ * todo: 2. Configure {@link PlatformTransactionManager} bean with name "transactionManager" * todo: 3. Enable transaction management */ +@Configuration +@ComponentScan("com.bobocode") +@EnableTransactionManagement public class RootConfig { + + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + return new JpaTransactionManager(entityManagerFactory); + } } diff --git a/hello-jpa-repository/src/main/java/com/bobocode/dao/UserRepository.java b/hello-jpa-repository/src/main/java/com/bobocode/dao/UserRepository.java index 69fd52d..a875fdd 100644 --- a/hello-jpa-repository/src/main/java/com/bobocode/dao/UserRepository.java +++ b/hello-jpa-repository/src/main/java/com/bobocode/dao/UserRepository.java @@ -8,6 +8,6 @@ *

* todo: 1. Configure {@link UserRepository} as {@link JpaRepository} for class User */ -public interface UserRepository extends JpaRepository { +public interface UserRepository extends JpaRepository { } diff --git a/user-service/src/main/java/com/bobocode/config/JpaConfig.java b/user-service/src/main/java/com/bobocode/config/JpaConfig.java index c9c133e..440899f 100644 --- a/user-service/src/main/java/com/bobocode/config/JpaConfig.java +++ b/user-service/src/main/java/com/bobocode/config/JpaConfig.java @@ -1,8 +1,14 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.orm.jpa.JpaVendorAdapter; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.Database; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import javax.sql.DataSource; @@ -16,11 +22,32 @@ * todo: 3. Configure {@link javax.persistence.EntityManagerFactory} bean with name "entityManagerFactory" * todo: 4. Enable JPA repository */ +@Configuration +@EnableJpaRepositories(basePackages = "com.bobocode.dao") public class JpaConfig { + @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } -} + + @Bean + public JpaVendorAdapter jpaVendorAdapter() { + HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + vendorAdapter.setDatabase(Database.H2); + vendorAdapter.setGenerateDdl(true); + vendorAdapter.setShowSql(true); + return vendorAdapter; + } + + @Bean("entityManagerFactory") + public LocalContainerEntityManagerFactoryBean localContainerEMF() { + LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); + emf.setDataSource(dataSource()); + emf.setJpaVendorAdapter(jpaVendorAdapter()); + emf.setPackagesToScan("com.bobocode.model"); + return emf; + } +} \ No newline at end of file diff --git a/user-service/src/main/java/com/bobocode/config/RootConfig.java b/user-service/src/main/java/com/bobocode/config/RootConfig.java index 52a639e..8ae7399 100644 --- a/user-service/src/main/java/com/bobocode/config/RootConfig.java +++ b/user-service/src/main/java/com/bobocode/config/RootConfig.java @@ -1,6 +1,13 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; /** * This class is provides root Java config for Spring application. @@ -10,6 +17,13 @@ * todo: 1. Configure {@link PlatformTransactionManager} bean with name "transactionManager" * todo: 2. Enable transaction management */ +@Configuration +@ComponentScan("com.bobocode") +@EnableTransactionManagement public class RootConfig { -} + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + return new JpaTransactionManager(entityManagerFactory); + } +} \ No newline at end of file diff --git a/user-service/src/main/java/com/bobocode/dao/UserRepository.java b/user-service/src/main/java/com/bobocode/dao/UserRepository.java index 1dd20ad..0a821af 100644 --- a/user-service/src/main/java/com/bobocode/dao/UserRepository.java +++ b/user-service/src/main/java/com/bobocode/dao/UserRepository.java @@ -2,6 +2,11 @@ import com.bobocode.model.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; /** * This interface represents a data access object (DAO) for {@link User}. @@ -13,6 +18,9 @@ * todo: 3. Create method that finds optional user by email fetching its address and roles using {@link org.springframework.data.jpa.repository.Query} * todo: 4. Add custom User repository interface */ -public interface UserRepository extends JpaRepository{ +public interface UserRepository extends JpaRepository, CustomUserRepository { + List findAllByAddressCity(String city); + @Query("select u from User u left join fetch u.address left join fetch u.roles where u.email = :email") + Optional findByEmailFetchRoles(@Param("email") String email); } diff --git a/user-service/src/main/java/com/bobocode/dao/impl/CustomUserRepositoryImpl.java b/user-service/src/main/java/com/bobocode/dao/impl/CustomUserRepositoryImpl.java new file mode 100644 index 0000000..34d4875 --- /dev/null +++ b/user-service/src/main/java/com/bobocode/dao/impl/CustomUserRepositoryImpl.java @@ -0,0 +1,38 @@ +package com.bobocode.dao.impl; + +import com.bobocode.dao.CustomUserRepository; +import com.bobocode.model.Role; +import com.bobocode.model.RoleType; +import com.bobocode.model.User; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; + +@Repository +@Transactional +public class CustomUserRepositoryImpl implements CustomUserRepository { + + @PersistenceContext + private EntityManager entityManager; + + + @Override + public void addRoleToAllUsers(RoleType roleType) { + List users = entityManager.createQuery("select u from User u left join fetch u.roles", User.class) + .getResultList(); + users.stream() + .filter(user -> hasNoRole(user, roleType)) + .forEach(user -> user.addRole(Role.valueOf(roleType))); + } + + private boolean hasNoRole(User user, RoleType roleType) { + return user.getRoles() + .stream() + .map(Role::getRoleType) + .noneMatch(type -> type.equals(roleType)); + } +} + diff --git a/user-service/src/main/java/com/bobocode/service/UserService.java b/user-service/src/main/java/com/bobocode/service/UserService.java index bd4b874..b15caf3 100644 --- a/user-service/src/main/java/com/bobocode/service/UserService.java +++ b/user-service/src/main/java/com/bobocode/service/UserService.java @@ -4,6 +4,8 @@ import com.bobocode.exception.EntityNotFoundException; import com.bobocode.model.RoleType; import com.bobocode.model.User; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -17,16 +19,27 @@ * todo: 3. In case user is not found by email, throw {@link EntityNotFoundException} with message "Cannot find user by email ${email}" * todo: 4. Implement {@link UserService#addRoleToAllUsers(RoleType)} using {@link UserRepository} */ +@Transactional +@Service public class UserService { + private final UserRepository userRepository; + + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Transactional(readOnly = true) public List findByCity(String city) { - throw new UnsupportedOperationException("Do your best and implement this method!"); + return userRepository.findAllByAddressCity(city); } + @Transactional(readOnly = true) public User getByEmail(String email) { - throw new UnsupportedOperationException("Do your best and implement this method!"); + return userRepository.findByEmailFetchRoles(email) + .orElseThrow(() -> new EntityNotFoundException(String.format("Cannot find user by email %s", email))); } public void addRoleToAllUsers(RoleType roleType) { - throw new UnsupportedOperationException("Do your best and implement this method!"); + userRepository.addRoleToAllUsers(roleType); } }