Mongodb #DBRef query spring - java

I my spring project, I am using two models with a reference.
A model user which has a reference on a token object.
#Document(collection = "user")
public class User {
#Id
public String id;
#DBRef
public Token token;
}
Then my Token object:
#Document(collection = "token")
public class Token {
#Id
public String id;
public String token;
}
I am trying to query a user from a token.
I tried to create a MongoRepository interface :
#Repository
public interface UserRepository extends MongoRepository<User, String> {
#Query(value="{ 'token.id' : ?0 }")
User findByTokenId(String id);
}
But that's not working. How can I create such kind or request ?

you can use:
#Repository
public interface UserRepository extends MongoRepository<User, String> {
#Query(value="{ 'token.id' : ?0 }")
User findAllByToken_Id(String id);
}

Related

Custom Repository using Entity Manager in Spring Boot

I observed that the .save() method executes an extra SELECT query to check whether the corresponding record already exists when the corresponding ID is not a AUTO INCREMENT one.
I tried to implement a repository for this kind of situation that will be extended by many JpaRepository interfaces which will be used across different stateless services and I would like to know if my code is safe - race conditions wise - accross multiple requests as I am not that comfortable using the EntityManager yet.
User Entity :
public class User {
#Id
#Column(name = "username", nullable = false, length = 45)
private String username;
#Column(name = "password", nullable = false, length = 256)
private String password;
}
Solution 1 :
public interface SimpleRepository<T> {
void persist(T entity);
}
public class SimpleRepositoryImpl<T> implements SimpleRepository<T> {
#PersistenceContext
EntityManager entityManager;
#Transactional
#Override
public void persist(T entity) {
entityManager.persist(entity);
}
}
User Repository :
public interface UserRepository extends JpaRepository<User, String>, SimpleRepository<User> {}
User Service :
#Service
#AllArgsConstructor
public class UserService {
private final UserRepository userRepository;
public void createUser(User user) {
this.userRepository.persist(user);
}
}
The same implementation will be followed across many different JPA Repositories and Services in the application.
If the solution above is not safe how about this one?
#Service
public class PersistenceService {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public <T> void persist(T entity) {
entityManager.persist(entity);
}
}
Which will turn my UserService and every other Service that is in need of the same functionality to :
#Service
#AllArgsConstructor
public class UserService {
private final PersistenceService persistenceService;
public void createUser(User user) {
this.persistenceService.persist(user);
}
}

Is there a way to extend a Spring Service in order to manage an inherited entity without duplicating code?

I'm playing with a Spring application with 2 controllers and 2 services that manages related entities and I would like to avoid duplicating code. I've got for example a Person class with his PersonRepository
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Person {
#Id
Long id;
String name;
String surname;
}
And his child User with his UserRepository
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class User extends Person {
String login;
String password;
}
I've a simple Person service whith business logic:
#Service
public class PersonService {
#Autowired
PersonRepository repo;
public Iterable<Person> getAll() {
// Busines Logic
return repo.findAll();
}
}
Is there a way to create a UserService extending or proxying PersonService and implementing some kind of repository "hiding"? Something like this:
#Service
public class UserService extends PersonService {
#Autowired
UserRepository repo;
}
that obviously gives this error:
Type mismatch: cannot convert from Iterable<Person> to Iterable<User> with a controller like this
#RestController
#RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public class DemoController {
#Autowired
UserService service;
#GetMapping
public void items() {
Iterable<User> persons = service.getAll();
return;
}
}
Try the following structure:
Common service and repository:
#NoRepositoryBean
public interface PersonRepository<T> extends JpaRepository<T, Long> {
}
public class PersonService<T extends Person> {
protected PersonRepository<T> repository;
public <R extends PersonRepository<T>> PersonService(R repository) {
this.repository = repository;
}
public Iterable<T> getAll() {
return repository.findAll();
}
}
For User entity:
public interface UserRepository extends PersonRepository<User> {
}
#Service
public class UserService extends PersonService<User> {
public UserService(UserRepository repository) {
super(repository);
}
public void additionalMethod() {
User user = repository.getOne(1L);
}
}
And I added Company entity by User entity example:
public interface CompanyRepository extends PersonRepository<Company> {
}
#Service
public class CompanyService extends PersonService<Company> {
public CompanyService(CompanyRepository repository) {
super(repository);
}
public void additionalMethod() {
Optional<Company> company = repository.findById(1L);
}
}

Jpa Repository save Inferred type 'S' for type parameter 'S' is not within its bound

I have entity user
#Entity
#Data
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
}
UserRepository
public interface UserRepository extends JpaRepository<UserRepository, Long> {
User findByUsername(String username);
}
Controller
#RestController
#RequestMapping("/user")
public class UserController {
private UserRepository userRepository;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public UserController(UserRepository userRepository, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userRepository = userRepository;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#PostMapping("/sign-up")
public void signUp(#RequestBody User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRepository.save(user);
}
}
In class UserController in signUp method userRepository.save(user) throw error Inferred type 'S' for type parameter 'S' is not within its bound; should implement 'Repository.UserRepository
Your Repository interface declaration isn't correct.
Change
public interface UserRepository extends JpaRepository<UserRepository, Long>
to
public interface UserRepository extends JpaRepository<User, Long>
For me, I got this error because save(list) method in the new version of spring boot does not support a List of objects as a parameter, so I replaced it with saveAll(list) so xRepository.saveAll(list)
The new version is generally 2.0 or higher having this change. They are restricting Save() method for Object. To save List type data we have to use saveAll().
Following is another working solution
return customRepository.findById(id).orElse(null);
Create the save method in the Repository Interface
void save(List<? extends User> user);
Reason: Teacher Liao's spring boot uses 1.4.1.RELEASE, and the new version is generally 2.0 or higher.
Solution: Replace the findOne method
return repo.findById(id).orElse(null);

Springboot API returns empty response

I built a simple Springboot API which is hooked up to a H2 db that contains some test data. However when I hit the API endpoint I get an empty response.
[{}]
When I debug my application the user object that is returned by the controller contains the user I am expecting.
UserController.java
#RestController
#RequestMapping("api/user")
public class UserController {
private UserService userService;
public UserController(#Autowired UserService userService){
this.userService = userService;
}
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public Set<User> getAllUsers(){
final Set<User> users = userService.getAllUsers();
return users;
}
}
UserRepo.java
public interface UserRepository extends CrudRepository<User, Long> {
#Query("SELECT usr from User usr")
Set<User> getAllUsers();
}
UserService.java
public interface UserService {
Set<User> getAllUsers();
}
UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
private final UserRepository repository;
public UserServiceImpl(#Autowired UserRepository userRepository){
this.repository = userRepository;
}
#Override
public Set<User> getAllUsers(){
final Set<User> users = repository.getAllUsers();
return users;
}
}
User.java
#Entity
#Getter
public class User {
#Id
private Long id;
private String username;
private String firstname;
private String lastname;
private String email;
private String role;
private String premium;
}
This was a rather strange issue of which I am still unable to say which. However, removing lombok's #getter and #setter annotations then implementing traditional ones fixed this issue.
You'll have to set the class members of User public to allow jackson serialise them, i.e.,
// User.java
#Entity
public class User {
#Id
public Long id;
public String username;
public String firstname;
public String lastname;
public String email;
public String role;
public String premium;
}
Note: if you'd like to not serialise a field, use #JsonIgnore instead of setting it as private, e.g.,
#Entity
public class User {
...
#JsonIgnore
public String role;
...
}
Just remove final and change Set to List as well.
and you really don`t need to do like this:
public UserController(#Autowired UserService userService)
Just remove this method and add Autowired up to userService filed.
Because final object can`t be cast to json string.
remove this as well:
produces = MediaType.APPLICATION_JSON_VALUE</h3>

Extending existing spring jpa repository functions

I'm using Spring to communicate with mysql db.
I've got an Entity class and an interface that extends CrudRepository.
Everything works great - read/write etc.
I want to 'extend' the findAll methods. I want to manipulate the received data from findAll before returning it.
user class:
#Entity
#Table(name = "user")
public class User
{
private String name;
private String age;
private String type;
getters/setters
}
repo:
#Repository
public interface UserRepo extends CrudRepository<User, Long> {
List<User> findAll();
Map<String, String> afterManipulatedFindAllData();
}
I want that afterManipulatedFindAllData() will manipulate findAll data as I like.
Is that possible?
added
after reviewing #BoristheSpider link:
interface UserRepository {
Map<String, String> afterManipulatedFindAllData();
}
class UserRepositoryImpl implements UserRepository{
public Map<String, String> afterManipulatedFindAllData() {
////how this method receive the 'findAll' data?//////
}
}
public interface UserRepo extends CrudRepository<User, Long>, UserRepository
{
List<User> findAll();
Map<String, String> afterManipulatedFindAllData();
}
Thanks a lot,
Avi
You can always define new methods in the repository by specifying a JPA query for them:
#Component
public interface UsersRepository extends JpaRepository<User, UUID> {
public List<User> findByEntityStatus(EntityStatus status);
#Query("from User user left outer join fetch user.areas where user.code = :code")
public User findByCode(#Param("code") String code);
}
Maybe this could work for you?

Categories