findByName isn't work [Spring boot] - spring

I have a problem with Spring boot.
I created Entity and Repository, but method findByName in Repository isn't work.
My url:
http://localhost:8080/student/search/findByName?name=Artem
In Google chrome: localhost not found, but search is mapped.
Entity:
#Getter #Setter
#Entity #Table(name = "Student")
public class Student extends BaseEntity{
private String name;
private String dateOfBirthDay;
private String sex;
private String phoneNumber;
}
BaseEntity:
#Getter
#Setter
#MappedSuperclass
public class BaseEntity {
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE) #Column protected Long id;
My Repository:
#RepositoryRestResource(collectionResourceRel = "student", path = "student")
public interface StudentRepository extends PagingAndSortingRepository<Student, Long> {
Student findByName(#Param("name") String name);
}
Application:
#SpringBootApplication
#EnableTransactionManagement
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application.yaml:
spring:
application:
name: students
datasource:
driverClassName: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/students
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: update
server:
port: 8080

I recommend you to create a resource class, works like controller. Here a simple example:
#RestController
#RequestMapping("/yourPath") //students, whatever
public class StudentsResource {
#Autowired
private StudentRepository studentRepository;
//type media that you want to show (json, xml...in this case is JSON)
#RequestMapping(method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
// <Student> is the entity, object
#RequestMapping(value = "/yourPath/{studentName}")
public ResponseEntity<Student> findByName(#pathVariable("studentName") String name) {
Student student = studentRepository.findByName(name);
if(student == null){
//handler your own exception here
}
//show the student as json object
return ResponseEntity.status(HttpStatus.OK).body(student);
}
Note: that's the resource class. But your problem is about localhost, so if you are using Spring Boot, see if your "application.properties" is correct. Here my example:
spring.datasource.url=jdbc:mysql://localhost:3306/yourDataBase
spring.datasource.username=yourUser
spring.datasource.password=yourPassword
spring.jpa.hibernate.ddl-auto=update //makes the spring create the database automatic!

Related

Spring boot properties with array

With an application.properties like that
application:
api:
clients:
api1:
url: http://url1
api2:
url: http://url2
basicAuth:
username: user2
password: password2
I can do
#Configuration
#ConfigurationProperties(prefix = "application.api")
#Data
public class ApiProperties {
private Map<String, Client> clients;
#Data
public static class Client {
private String url;
private BasicAuth basicAuth;
}
#Data
public static class BasicAuth {
private String username;
private String password;
}
}
And it is working.
But is there a way of retrieving only one client ? So In place of
private Map<String, Client> clients;
I'd like to have something like
#Value("${application.api.clients['api1']}")
private Client client1;
I tried multiple ways of writing it but I always have Could not resolve placeholder...
Is there a solution ?
Looks like this is not possible with nested properties or hierarchal properties.
#Value("${application.api.clients['api1']}")
private Client client1;
But you can try this if you want to retrieve only one client.
#Configuration
#ConfigurationProperties(prefix = "application.api.clients")
#Data
public class ApiProperties {
private Client api1;
#Data
public static class Client {
private String url;
private BasicAuth basicAuth;
}
#Data
public static class BasicAuth {
private String username;
private String password;
}
}

JPA issue (lazy loading? eager ?)

Iam building a simple Spring Boot app, with 2 entities:
- Student model
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Student {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String password;
private boolean active;
private Date dob;
private String roles;
#ManyToOne
private Training training;
}
- Training model
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Training {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int duration;
#OneToMany(mappedBy = "training")
#JsonIgnore
private Collection<Student> students;
}
EDIT
I run the app by adding 2 resources in the db:
public static void main(String[] args) {
SpringApplication.run(MsSchoolingSbApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
Training t1=trainingRepo.save(new Training(null,"php", 20, null));
Training t2=trainingRepo.save(new Training(null,"java", 20, null));
Student st=new Student(null, "XXXX", "ZZZZ", true,new Date(),"ADMIN",t1);
Student st2=new Student(null, "XXXXX2", "ZZZZZ2", true,new Date(),"USER",t2);
studentRepo.save(st);
studentRepo.save(st2);
}
END EDIT
EDIT 2
- StudentRepo
#RepositoryRestController
public interface StudentRepo extends JpaRepository<Student, Long>{
public List<Student> findByNameStartsWith(String name);
Optional<Student> findByName(String name);
}
- TrainingRepo
#RepositoryRestController
public interface TrainingRepo extends JpaRepository<Training, Long> {
}
END EDIT 2
i've tried to put fetch = FetchType.EAGER or LAZY, i've also added #JsonIgnore but as soon as i fill the db with new data (trainings and students) and run the app, i get this message:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.schooling.models.Training.students, could not initialize proxy - no Session
What am i doing wrong ?
The problem you got must have related to how you use those 2 entities so you need to provide more information about how you use it.
You might want to look out for your problem in this tutorial: https://www.baeldung.com/hibernate-initialize-proxy-exception
Do not use Lombok's #Data annotation on #Entity classes.
Reason: #Data generates hashcode(), equals() and toString() methods that use the generated getters. Using the getter means of course fetching new data even if the property was marked with FetchType=LAZY.
Somewhere along the way hibernate tries to log the data with toString() and it crashes
EDIT
you can exclude the relation from the toString method by adding, for example in my case:
#ToString(exclude = {"students"})

CascadeType Merge is ignored when Persist is set

Hy all
I'm having a hard time solving the following spring jpa problem.
Let's say I have the following simple data model (two entities with a one direction relationship between the two)
#Accessors(chain = true) #Getter #Setter #NoArgsConstructor #AllArgsConstructor
#MappedSuperclass
public class AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Version
private Long version;
}
#Accessors(chain = true) #Getter #Setter #NoArgsConstructor #AllArgsConstructor
#Entity
public class Entity1 extends AbstractEntity {
private String name;
}
#Accessors(chain = true) #Getter #Setter #NoArgsConstructor #AllArgsConstructor
#Entity
public class Entity2 extends AbstractEntity {
private String name;
#ManyToOne(cascade={ALL})
private Entity1 entity1;
}
and the following plumbing to store them
public interface Entity1Dao extends JpaRepository< Entity1, Long >, JpaSpecificationExecutor< Entity1 > {
Entity1 findByName(String name);
}
public interface Entity2Dao extends JpaRepository< Entity2, Long >, JpaSpecificationExecutor< Entity2 > {
Entity2 findByName(String name);
}
#Service
public class StoreService {
#Autowired
Entity1Dao dao1;
#Autowired
Entity2Dao dao2;
#Transactional
public Entity1 saveEntity1(Entity1 e) {
return dao1.save(e);
}
#Transactional
public Entity2 saveEntity2(Entity2 e) {
return dao2.save(e);
}
public Entity1 loadEntity1ByName(String name) {
return dao1.findByName(name);
}
}
#SpringBootApplication
public class JpaDemoApplication {
public static void main(String[] args) {
SpringApplication.run(JpaDemoApplication.class, args);
}
}
And the following test
#SpringBootTest
#TestMethodOrder(value = MethodOrderer.OrderAnnotation.class)
class JpaDemoApplicationTests {
#Autowired
StoreService store;
#Test
#Order(1)
void contextLoads() {
assertThat(store).isNotNull();
}
#Test
#Order(2)
void insertEntity1() {
store.saveEntity1(new Entity1("test entity1"));
Entity1 saved = store.loadEntity1ByName("test entity1");
assertThat(saved).isNotNull().hasNoNullFieldsOrProperties();
}
#Test
#Order(4)
void insertEntity2WithNewEntity1() {
store.saveEntity2(new Entity2("with new entity1", new Entity1("new entity1")));
}
#Test
#Order(5)
void insertEntity2WithExistingEntity1() {
store.saveEntity2(new Entity2("with saved entity1", store.loadEntity1ByName("test entity1")));
}
}
the last test (i.e. insertEntity2WithExistingEntity1) fails with the following exception
org.hibernate.PersistentObjectException: detached entity passed to
persist: com.example.jpaDemo.Entity1
If I change the CascadeType in Entity2 to MERGE, that test passes but the insertEntity2WithNewEntity1 fails with the following exception
org.hibernate.TransientPropertyValueException: object references an
unsaved transient instance - save the transient instance before
flushing : com.example.jpaDemo.Entity2.entity1 ->
com.example.jpaDemo.Entity1
I've tried multiple combination of cascading types bute it seems that as soon as PERSIST is used, the last test fails (and ALL includes PERSIST).
I would have expected that if MERGE and PERSIST are set, they would both be active but form the test it looks like MERGE is ignored when PERSIST is set.
Any clues, tips, hints at what I'm doing wrong so that both tests run???
EDIT
The tests are suppose to mimick the behaviour of a REST service endpoint reveiving and saving json reprensentation of an Entity1.
The json for the third test would be
{ name: "with new entity1", entity1: { name: "new entity1"}}
The json for the fourth would be
{ name: "with new entity1", entity1: { id: 1, version: 0, name: "test entity1"}}
JPA should persists the entity1 in the third test because it's id is null but should merge the one in the fourth test because it's id is not null.
I am however unable to do both, it's either one or the other.
EDIT 2
I've modified Entity1 slightly to have a reference to the list of Entity2 associated to it and annotated it with #OneToMany and the same cascading type as in Entity2 and it's the same behavior.
When I set the cascading type to MERGE and only Merge, I'm able to save a new entity that has a reference with an existing one but I can't save a new entity with a reference to a new one.
When I set the cascading type to PERSIST (i.e PERSIST on its own, PERSIST and MERGE or ALL), it's the oppposit; I can save a new entity with a reference to anther new entity but I can't save a new entity with a reference to an already existing one.
So it's seem that when PERSIST is set, it overrides the behavior of MERGE. That, to me, is a bug. Is it not?
I've uploaded the source to github in case you want to experiment or take a look at it yourself. https://github.com/willix71/persistVsMerge.git
You need to add #Transactional on your last test. The entity loaded is detached as there is no outer transaction, you can't persist it.
#Test
#Order(5)
#Transactional
void insertEntity2WithExistingEntity1() {
store.saveEntity2(new Entity2("with saved entity1", store.loadEntity1ByName("test entity1")));
}
I'm not sure if this is relevant anymore, but the code below works as I would expect. Removing "cascade = CascadeType.PERSIST" will fail the persist test with "object references an unsaved transient instance".
I also noticed in your github repo that you are attempting to do cascading both from parent to child and child to parent. I think this is the root cause of your issues.
Entities:
#Entity
#Table(name = "users")
#Getter
#Setter
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
UUID id;
#ManyToOne(cascade = CascadeType.PERSIST)
Address address;
}
#Entity
#Getter
#Setter
#NoArgsConstructor
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#OneToMany(mappedBy = "address")
List<User> user;
}
Repositories:
public interface UserRepository extends JpaRepository<User, UUID> {
}
public interface AddressRepository extends JpaRepository<Address, UUID> {
}
Tests:
#DataJpaTest
#Import(DataSourceConfig.class)
class UserRepositoryTest {
#Autowired
private UserRepository userRepository;
#Autowired
private AddressRepository addressRepository;
#Test
void testMerge() {
var address = new Address();
addressRepository.save(address);
var user = new User();
user.setAddress(address);
userRepository.save(user);
assertThat(userRepository.findAll()).contains(user);
assertThat(addressRepository.findAll()).contains(address);
}
#Test
void testPersist() {
var address = new Address();
var user = new User();
user.setAddress(address);
userRepository.save(user);
assertThat(userRepository.findAll()).contains(user);
assertThat(addressRepository.findAll()).contains(address);
}
}

When does the hibernate session gets closed

I have created the following entities.
#Entity
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "student")
private List<Book> books;
}
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "STUDENT_ID")
private Student student;
}
My controller looks like this
#RestController
public class Controller {
MyService myService;
public Controller(MyService myService) {
this.myService = myService;
}
#GetMapping("student")
public List<Book> getBooksForStudent(Long id) {
return myService.getBooks(id);
}
}
The service is as follows.
public class MyService {
#Autowired
private StudentRepo studentRepo;
public List<Book> getStudent(Long id) {
Optional<Student> studentOptional = studentRepo.findById(id);
return studentOptional.map(Student::getBooks).orElseThrow(IllegalArgumentException::new);
}
}
I am getting the list of books as expected. But as I'm having lazy loaded list for books I should be getting a LazyInitializationException. I have not added transnational to the method and I'm returning the list of books from the entity itself without mapping it to a DTO. Why is the hibernate session not getting closed after the end of the method?
#RestController is transactional by default. Spring boot automatically registers an OpenEntityManagerInViewInterceptor when you use a web application/you use JPA. Refer #RestController methods seem to be Transactional by default, Why?

Spring Data postgresql 10 insertion does not work

I am working on spring boot application with RestController, Service a Repository and an Entity.
My problem is when I call the web service to save my data in the data base, it seems it works fine and there is no exception thrown but when I check my data base I find that the table was created but I find no data saved. and here is what I get in the output(for each element in my list):
Hibernate:
insert
into
table_name
(columnOne, columnTwo)
values
(?, ?)
Here is my code:
RestController:
#RestController
#RequestMapping(path = "/api/")
public class myController {
#Autowired
private MyService myService;
#PostMapping(path="/inject/{year}")
public void myControllerMethod(#PathParam("year") Year year) {
this.myService.myServiceMethod(year);
}
}
Service:
#Service
public class MyService {
#Autowired
MyRepository myRepository;
public void myServiceMethod(Year year) {
List<MyEntity> myEntityList = this.parseMyEntityList(year);
this.myRepository.save(myEntityList)
}
}
Repository:
#Repository
public interface MyRepository extends CrudRepository<MyEntity, Long>, JpaSpecificationExecutor<InseeLibelle> {
}
Entity:
#Entity
#Table(name = "table_name", indexes = {
#Index(name = "columnOne_idx", columnList = "columnOne"),
#Index(name = "columneTwo_idx", columnList = "columnTwo"),
})
public class MyEntity{
#JsonIgnore
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long columnId;
#Column
private Integer columnOne;
#Column
private String columnTwo;
public Integer getColumnOne() {
return columnOne;
}
public void setColumnOne(Integer columnOne) {
this.columneOne = colmunOne;
}
public String getColumnTwo() {
return columnTwo;
}
public void setColumnTwo(String columnTwo) {
this.columnTwo = columnTwo;
}
}
I tried to add this line in the repository but it does not work too:
<S extends MyEntity> Iterable<S> save(Iterable<S> entities) ;
Perhaps the problem is with the pgAdmin (like my case), it does not show the data but they exist in the database, try findAll method in the repository or check them with select * directly.

Resources