Springboot Persisting Authentication on different Catalog - spring-boot

I'm using SpringBoot and enabled a persistent authentication mechanism by setting
#Bean
public PersistentTokenRepository persistentTokenRepository()
{
JdbcTokenRepositoryImpl tokenRepo = new JdbcTokenRepositoryImpl();
tokenRepo.setDataSource(dataSource);
return tokenRepo;
}
Now, dataSource has two catalogs, namely "data" and "useraccount". By default PersistentTokenRepository looks on the main catalog that is "data" but I want to select "useraccount" to store the "persistent_logins" table. Hence, I write:
#Entity(name="PersistentLogin")
#Table(name = "persistent_logins", catalog = "useraccount")
#Data
public class PersistentLogin implements Serializable
{
#Id
private String series;
private String username;
private String token;
private Timestamp last_used;
}
The problem is that "persistent_logins" is always searched in the main catalog. Is there any way to change this setting?

I solved by overring Solved by overridding JdbcTokenRepositoryImpl.java and modifying as desired.

Related

How do I insert data into 2 tables in the same database using Spring Boot Crudrepository?

I want to be able to create a new account for my application. I have an account class which represents one entity and another class that represents personal information of the account. In order to create the new account and have it be in the database I want to add some information into the account table and some information into the PersonalInfo table as detailed in the classes below. How do I do this with a CrudRespository interface. As I understand it, the crudrepository can interact with one table in the database. In my example that would be Accounts. This is fine because most of my checking and communicating will be with the accounts table. But for when I am creating a new account I need to add the data that will be given into two tables. Do I have to make manual queries and add it as a method in there?
#Entity
#Component
public class Account {
#Id
private int accountNum;
private String accountType;
private int accountBalance;
private String accountStatus;
#Entity
#Component
public class PersonalInfo {
#Id
private int accountNum;
private String firstName;
private String lastName;
private String SSN;
private String streetName;
private String city;
private String state;
private String zipcode;
#RepositoryRestResource(collectionResourceRel="accounts",path="accounts")
public interface AccountsDB extends CrudRepository<Account, Integer>{
}
Just create a repository for PersonalInfo and invoke two save() methods (of the two different repositories respectively) with the two created entities respectively.
Just make sure to set the identical ids (accountNum) for these two entities.
Or, you could create a service to do it for you, like so:
public interface AccountAndPersonalInfoService {
void save(Account account, PersonalInfo personalInfo);
}
#Service
public class AccountAndPersonalInfoServiceImpl implements AccountAndPersonalInfoService {
#Autowired
private AccountsDB accountsDB;
#Autowired
private PersonalInfoDB personalInfoDB;
#Override
void save(Account account, PersonalInfo personalInfo) {
if (account.getAccountNum() == personalInfo.getAccountNum()) {
accountsDB.save(account);
personalInfoDB.save(personalInfo);
} else throw new IllegalArgumentException("The ids of the entities do not match.");
}
}

Redis #Reference does not work in Spring Data Redis

I am facing issues while implemeting #Reference in Spring Boot + Spring Data Redis. Address is a List in Employee and when I saved the office and home address and I was expecting the data to be saved with the Employee. But data did not get saved and hence unable to search the Address using street.
Employee.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("employees")
public class Employee {
#Id #Indexed
private String id;
private String firstName;
private String lastName;
#Reference
private List<Address> addresses;
}
Address.java
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#RedisHash("address")
public class Address {
#Id
private String id;
#Indexed
private String street;
private String city;
}
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeAdressTest extends RepositoryTestSupport{
#Autowired private EmployeeRepository employeeRepository;
#Before
public void setUp() throws JsonProcessingException {
Address home = Address.builder().street("ABC Street").city("Pune").build();
Address offc = Address.builder().street("XYZ Street").city("Pune").build();
Employee employee1 = Employee.builder().firstName("Raj").lastName("Kumar").addresses(Arrays.asList(home, offc)).build();
employeeRepository.save(employee1);
List<Employee> employees = employeeRepository.findByAddresses_Street("XYZ Street");
System.out.println("EMPLOYEE = "+employees);
}
#Test
public void test() {
}
}
Spring Doc:
8.8. Persisting References
Marking properties with #Reference allows storing a simple key reference instead of copying values into the hash itself. On loading from Redis, references are resolved automatically and mapped back into the object, as shown in the following example:
Example 30. Sample Property Reference
_class = org.example.Person
id = e2c7dcee-b8cd-4424-883e-736ce564363e
firstname = rand
lastname = al’thor
mother = people:a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56
Reference stores the whole key (keyspace:id) of the referenced object.
?
Spring Data Redis requires you to save the objects stored in home and office separately from the referencing object employee1.
This is (now) stated in the official documentation at the very end of chapter 8.8: https://docs.spring.io/spring-data-redis/docs/current/reference/html/#redis.repositories.references
So if you save home and office to the database before saving employee1 you should be fine.
The same btw holds valid for updates you make to referenced objects later on. Just saving the referencing object alone does not save the updates on the referenced objects.

Select one column using Spring Data JPA

Does anyone have any idea how to get a single column using Spring Data JPA? I created a repository like below in my Spring Boot project, but always get the {"cause":null,"message":"PersistentEntity must not be null!"} error when accessing the Restful URL.
#RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UsersRepository extends CrudRepository<Users, Integer> {
#Query("SELECT u.userName FROM Users u")
public List<String> getUserName();
}
Then if I access the Restful URL like ../users/search/getUserName, I get the error:
{"cause":null,"message":"PersistentEntity must not be null!"}
Create a Projection interface
public interface UserNameOnly {
String getUserName();
}
Then in your repository interface return that type instead of the user type
public interface UserRepository<User> extends JpaRepository<User,String> {
List<UsernameOnly> findNamesByUserNameNotNull();
}
The get method in the projection interface must match a get method of the defined type on the JPA repository, in this case User.
The "findBySomePropertyOnTheObjectThatIsNotNull" allows you to get a List of the entities (as opposed to an Iterable) based on some criteria, which for a findAll can simply be if the unique identifier (or any other NonNull field) is not null.
Concept is : In your entity class create a constructor with only required instant variables. And use that constructor in the repository method shown below.
Lets say you have a interface Repository like below
Repository implementation:
public interface UserRepository<User> extends JpaRepository<User,String>
{
#Query(value = "select new com.org.User(usr.userId) from User usr where usr.name(:name)")
List<User> findUserIdAlone(#Param("name") String user);
}
In Controller
#RestController
public class UserController
{
#Autowired
private UserRepository<User> userRepository;
#Res
public ResponseEntity<User> getUser(#PathVariable("usrname") String userName)
{
User resultUser = usrRepository.findUserIdAlone(userName);
return ResponseEntity.ok(resultUser);
}
}
public class User
{
private String userId,userName;
public User(String userId)
{
this.userId=userId;
}
// setter and getters goes here
}
This Works for me.
public interface UserDataRepository extends JpaRepository<UserData, Long> {
#Query(value = "SELECT emp_name FROM user_data", nativeQuery = true)
public List<Object[]> findEmp_name();
}
System.out.println("data"+ userDataRepository.findEmp_name());
The above line gave me this result :
data[abhijeet, abhijeet1, abhijeet2, abhijeet3, abhijeet4, abhijeet5]
If you want to only return a single column you should look at Projections and Excerpts which will allow you to filter specific columns and other things that are usefule.
If you need list all of the users, try select userName from Users, if you need one user use "where" look at spring data JPA http://docs.spring.io/spring-data/jpa/docs/current/reference/html/ , try change CrudRepository to JpaRepository
It is possible to provide custom implementations of methods in a Spring Data JPA repository, which enables complete control on queries and return types. The approach is as follows:
Define an interface with the desired method signatures.
Implement the interface to achieve the desired behavior.
Have the Repository extend both JpaRepository and the custom interface.
Here is a working example that uses JpaRepository, assuming a user_table with two columns, user_id and user_name.
UserEntity class in model package:
#Entity
#Table(name = "user_table")
public class UserEntity {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#Column(name = "user_name")
private String userName;
protected UserEntity() {}
public UserEntity(String userName) {
this.userName = userName;
// standard getters and setters
}
Define interface for the custom repository in the repository package:
public interface UserCustomRepository {
List<String> findUserNames();
}
Provide implementation class for the custom interface in the repository package:
public class UserCustomRepositoryImpl implements UserCustomRepository {
// Spring auto configures a DataSource and JdbcTemplate
// based on the application.properties file. We can use
// autowiring to get a reference to it.
JdbcTemplate jdbcTemplate;
#Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// Now our custom implementation can use the JdbcTemplate
// to perform JPQL queries and return basic datatypes.
#Override
public List<String> findUserNames() throws DataAccessException {
String sql = "SELECT user_name FROM user_table";
return jdbcTemplate.queryForList(sql, String.class);
}
}
Finally, we just need to have the UserRepository extend both JpaRepository and the custom interface we just implemented.
public interface UserRepository extends JpaRepository<UserEntity, Long>, UserCustomRepository {}
Simple test class with junit 5 (assuming the database is initially empty):
#SpringBootTest
class UserRepositoryTest {
private static final String JANE = "Jane";
private static final String JOE = "Joe";
#Autowired
UserRepository repo;
#Test
void shouldFindUserNames() {
UserEntity jane = new UserEntity(JANE);
UserEntity joe = new UserEntity(JOE);
repo.saveAndFlush(jane);
repo.saveAndFlush(joe);
List<UserEntity> users = repo.findAll();
assertEquals(2, users.size());
List<String> names = repo.findUserNames();
assertEquals(2, names.size());
assertTrue(names.contains(JANE));
assertTrue(names.contains(JOE));
}
}

Spring Boot + JPA + Lazy bi-directional collection testing

I'm new to JPA and Spring Data and I've faced problem with testing my application. I have two entities in my Spring boot application:
#Getter
#Setter
#Entity
public class User extends SomeBasicEntity {
#NotNull
#Column(unique = true)
private String login;
#NotNull
private String password;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
#JsonManagedReference
private List<Role> roles;
}
#Getter
#Setter
#Entity
#Table(name = "ROLE")
public class Role extends SomeBasicEntity {
#NotNull
private String name;
#ManyToOne
#NotNull
#JsonBackReference
private User user;
}
I have implemented dedicated JPA repositories for them (as JpaRepository).
I have also implemented transactional facade for the management:
#Service
#Transactional
public class Facade {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
public User addNewUser(User user) {
return userRepository.save(user);
}
public Role addNewRole(Role role, User user) {
role.setUser(user);
return roleRepository.save(role);
}
public User findUserByLogin(String login) {
User user = userRepository.findByLogin(login);
if (user != null) {
return user;
} else {
throw new FacadeRuntimeException("User " + login + " does not exists");
}
}
}
Finally, I've created RestController for using the facade (I've hardcoded login name value just for test purposes):
#RestController
#RequestMapping(value = "/users")
public class UserController {
#Autowired
private Facade facade;
#RequestMapping(value = "/login", method = RequestMethod.GET)
public User getUserByLogin() {
User user = facade.findUserByLogin("jahu");
return user;
}
}
And now when I run the application, use facade methods to create user and role (code is irrelevant so I dont paste it here) and check REST response on localhost/users/login there is properly serialized User object WITH list of roles (with single role I've created actually).
Question 1: Why roles are present in Json object whereas I didn't explictly call getRoles on the user object? With lazy fetch type I believe collection should be retrived only when getter is called (maybe JSON serializer is calling the method?)
Nevertheless, I have second problem as I want to test my facade with jUnit (on h2 db), however in test method the roles on User object are always null (even if I explicltly call getter):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = FacadeApplication.class)
#Transactional
public class FacadeTest {
private static final String USER_LOGIN = "jahu";
private static final String ROLE_NAME = "role name";
#Autowired
Facade sut;
#Before
public void setUp() throws Exception {
User user = new User();
user.setLogin(USER_LOGIN);
user.setPassword("jahu");
user = sut.addNewUser(user);
Role role = new Role();
role.setName(ROLE_NAME);
sut.addNewRole(role, user);
}
#Test
public void shouldFindUserRoles() {
User user = sut.findUserByLogin(USER_LOGIN);
assertThat(user).isNotNull();
assertThat(user.getLogin()).isEqualTo(USER_LOGIN);
List<Role> roles = user.getRoles(); // HERE I call the getter
assertThat(roles).isNotNull().isNotEmpty();
}
}
Question 2: Why can I not access roles in test context even though I am using the same method as in RestController (where roles are always obtained)? Without it I am not able to fully test my app and it concerns me very much.
Note: entity names are just for description of the problem, so please don't suggest that I should remodel my entities in order to assign Role to User.

Spring Data Neo4J #Indexed(unique = true) not working

I'm new to Neo4J and I have, probably an easy question.
There're NodeEntitys in my application, a property (name) is annotated with #Indexed(unique = true) to achieve the uniqueness like I do in JPA with #Column(unique = true).
My problem is, that when I persist an entity with a name that already exists in my graph, it works fine anyway.
But I expected some kind of exception here...?!
Here' s an overview over basic my code:
#NodeEntity
public abstract class BaseEntity implements Identifiable
{
#GraphId
private Long entityId;
...
}
public class Role extends BaseEntity
{
#Indexed(unique = true)
private String name;
...
}
public interface RoleRepository extends GraphRepository<Role>
{
Role findByName(String name);
}
#Service
public class RoleServiceImpl extends BaseEntityServiceImpl<Role> implements
{
private RoleRepository repository;
#Override
#Transactional
public T save(final T entity) {
return getRepository().save(entity);
}
}
And this is my test:
#Test
public void testNameUniqueIndex() {
final List<Role> roles = Lists.newLinkedList(service.findAll());
final String existingName = roles.get(0).getName();
Role newRole = new Role.Builder(existingName).build();
newRole = service.save(newRole);
}
That's the point where I expect something to go wrong!
How can I ensure the uniqueness of a property, without checking it for myself??
P.S.: I'm using neo4j 1.8.M07, spring-data-neo4j 2.1.0.BUILD-SNAPSHOT and Spring 3.1.2.RELEASE.
I walked into the same trap... as long as you create new entities, you will not see the exception - the last save()-action wins the battle.
Unfortunately, the DataIntegrityViolationException will be raised only in case of update an existing entity!
A detailed description of that behaviour can be found here:
http://static.springsource.org/spring-data/data-graph/snapshot-site/reference/html/#d5e1035
If you are using SDN 3.2.0+ use the failOnDuplicate attribute:
public class Role extends BaseEntity
{
#Indexed(unique = true, failOnDuplicate = true)
private String name;
...
}

Resources