I am trying to add #NotNull constraint into my Person object but I still can #POST a new Person with a null email. I am using Spring boot rest with MongoDB.
Entity class:
import javax.validation.constraints.NotNull;
public class Person {
#Id
private String id;
private String username;
private String password;
#NotNull // <-- Not working
private String email;
// getters & setters
}
Repository class:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends MongoRepository<Person, String> {
}
Application class:
#SpringBootApplication
public class TalentPoolApplication {
public static void main(String[] args) {
SpringApplication.run(TalentPoolApplication.class, args);
}
}
pom.xml
...
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
...
When I #POST a new object via Postman like:
{
"username": "deadpool",
"email": null
}
I still get STATUS 201 created with this payload:
{
"username": "deadpool",
"password": null,
"email": null
....
....
}
I had the same problem, but just enabling validation didn't work for me, this did work with both JPA and MongoDb to save anyone else spending ages on this. Not only does this get validation working but I get a nice restful 400 error rather than the default 500.
Had to add this to my build.gradle dependencies
compile('org.hibernate:hibernate-validator:4.2.0.Final')
and this config class
#Configuration
public class CustomRepositoryRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {
#Bean
public Validator validator() {
return new LocalValidatorFactoryBean();
}
#Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("afterCreate", validator());
validatingListener.addValidator("beforeCreate", validator());
validatingListener.addValidator("afterSave", validator());
validatingListener.addValidator("beforeSave", validator());
}
}
i found it better to make my own version of #NotNull annotation which validates empty string as well.
#Documented
#Constraint(validatedBy = NotEmptyValidator.class)
#Target({ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface NotEmpty {
String message() default "{validator.notEmpty}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class NotEmptyValidator implements ConstraintValidator<NotEmpty, Object> {
#Override
public void initialize(NotEmpty notEmpty) { }
#Override
public boolean isValid(Object obj, ConstraintValidatorContext cxt) {
return obj != null && !obj.toString().trim().equals("");
}
}
You can either use the following code for validating
#Configuration
#Import(value = MongoAutoConfiguration.class)
public class DatabaseConfiguration extends AbstractMongoConfiguration
{
#Resource
private Mongo mongo;
#Resource
private MongoProperties mongoProperties;
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Override
protected String getDatabaseName() {
return mongoProperties.getDatabase();
}
#Override
public Mongo mongo() throws Exception {
return mongo;
}
}
Normally, the #RestRepository will resolve into a controller than handles validation by itself, except if you Override the default behavior or it by including some #HandleBeforeSave, #HandleBeforeCreate, ... into your code.
A solution is to remove the #HandleBeforeSave, #HandleBeforeCreate, ...
and then spring will handle the validation again.
Or if you want to keep them, you can provide a handler for any object validation like this:
#Component
#RepositoryEventHandler
public class EntityRepositoryEventHandler {
#Autowired
private Validator validator;
#HandleBeforeSave
#HandleBeforeCreate
public void validate(Object o) {
Set<ConstraintViolation<Object>> violations = this.validator.validate(o);
if (!violations.isEmpty()) {
ConstraintViolation<Object> violation = violations.iterator().next();
// do whatever your want here as you got a constraint violation !
throw new RuntimeException();
}
}
}
Related
I have a problem with Spring Boot application. I want to connect a MongoDB database and a MySql database in my Spring boot application. I would to know if it is possible, in positive case How I can make this multiple connection. I had made a try based on an example with Mysql and Post without success. So I'm wondering if someone have an easy example to know the method.
thanks
It is possible to do this.you will have create different configuration for different datasources. This link has good examples on that
http://www.baeldung.com/spring-data-jpa-multiple-databases
Another useful stackoverflow question: Spring Boot Configure and Use Two DataSources
To get started with mongo and mysql , you can follow example from spring.io guides.
https://spring.io/guides/gs/accessing-data-mongodb/
https://spring.io/guides/gs/accessing-data-mysql/
EDIT :
I have created this one example, merging two samples above
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import hello.model.Customer;
import hello.model.User;
import hello.mongodao.CustomerRepository;
import hello.mysqldao.UserRepository;
#EnableMongoRepositories(basePackageClasses = CustomerRepository.class)
#EnableJpaRepositories (basePackageClasses = UserRepository.class)
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
private CustomerRepository repository;
#Autowired
private UserRepository userRepository;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println("getting data from Mongo");
repository.deleteAll();
// save a couple of customers
repository.save(new Customer("Alice", "Smith"));
repository.save(new Customer("Bob", "Smith"));
// fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : repository.findAll()) {
System.out.println(customer);
}
System.out.println();
// fetch an individual customer
System.out.println("Customer found with findByFirstName('Alice'):");
System.out.println("--------------------------------");
System.out.println(repository.findByFirstName("Alice"));
System.out.println("Customers found with findByLastName('Smith'):");
System.out.println("--------------------------------");
for (Customer customer : repository.findByLastName("Smith")) {
System.out.println(customer);
}
System.out.println("gettting data from mysql");
userRepository.deleteAll();
// save a couple of customers
userRepository.save(new User("Alice", "Alice#Smith.com"));
userRepository.save(new User("Bob", "Bob#Smith.com"));
// fetch all customers
System.out.println("Users found with findAll():");
System.out.println("-------------------------------");
for (User user : userRepository.findAll()) {
System.out.println(user);
}
}
}
CustomerRepository.java
package hello.mongodao;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import hello.model.Customer;
public interface CustomerRepository extends MongoRepository<Customer, String> {
public Customer findByFirstName(String firstName);
public List<Customer> findByLastName(String lastName);
}
UserRepository.java
package hello.mysqldao;
import org.springframework.data.repository.CrudRepository;
import hello.model.User;
// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete
public interface UserRepository extends CrudRepository<User, Long> {
}
Customer.java
package hello.model;
import org.springframework.data.annotation.Id;
public class Customer {
#Id
public String id;
public String firstName;
public String lastName;
public Customer() {}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return String.format(
"Customer[id=%s, firstName='%s', lastName='%s']",
id, firstName, lastName);
}
}
User.java
package hello.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity // This tells Hibernate to make a table out of this class
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String email;
public User() {
// TODO Auto-generated constructor stub
}
public User(String string, String string2) {
// TODO Auto-generated constructor stub
name = string;
email = string2;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return String.format(
"User[id=%s, name='%s', email='%s']",
id, name, email);
}
}
application.properties
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:mysql://localhost:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.data.mongodb.uri=mongodb://localhost:27017/local
You really don't need to make additional config and property files because MongoDB has different property names than sql so all you will need is an application.properties file
application.properties
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/dbName?useUnicode=yes&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=
spring.data.mongodb.uri=mongodb://localhost:27017
spring.data.mongodb.database=dbName
example models
MongoDB document
import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.Id;
#Document("Gyros")
public class Gyros {
public Gyros(String description) {
this.description = description;
}
#Id
public String id;
public String description;
}
Mysql JPA entity
import javax.persistence.*;
#Entity
#Table(name = "Kebab")
public class Kebab {
public Kebab(String description) {
this.description = description;
}
public Kebab() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int id;
public String description;
}
MongoDB repository
#Repository
public interface GyrosRepository extends MongoRepository<Gyros, String> {
}
Mysql Jpa repository
#Repository
public interface KebabRepository extends JpaRepository<Kebab, Integer> {
}
TestService
#org.springframework.stereotype.Service
public class Service {
private final GyrosRepository gyrosRepository;
private final KebabRepository kebabRepository;
#Autowired
public Service(GyrosRepository gyrosRepository, KebabRepository kebabRepository) {
this.gyrosRepository = gyrosRepository;
this.kebabRepository = kebabRepository;
}
#PostConstruct
void test() {
this.gyrosRepository.insert(new Gyros("ham ham"));
this.kebabRepository.saveAndFlush(new Kebab("yum yum"));
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>stack</artifactId>
<version>1.0-SNAPSHOT</version>
<name>stackoverflow</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
I also faced the same kind of problem once. I had to connect my spring boot application to two different databases. One was Mongo db and other was Postgres db.
You can see that i have used both JPA as well as spring-boot-starter-data-mongodb. Still my project is running absolutely fine.Hope for you also it work successfully. There are suggestions over the internet to not use JPA but i am not able to use JPA repository without include JPA.
Here I am posting the solution which worked for me.
Hope it helps someone:
application.properties file:
MONGODB (MongoProperties)
spring.data.mongodb.uri=mongodb://XX.XX.XX.XX:27017/testdb
#POSTGRES properties
spring.datasource.platform=postgres
spring.datasource.url= jdbc:postgresql://localhost:5432/database_name
spring.datasource.username=postgres_usr_name
spring.datasource.password=postgres_pwd
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
My pom dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
To access my data Using Repositories:
(i): MONGO REPOSITORY
import org.springframework.data.mongodb.repository.MongoRepository;
public interface MRepositories extends MongoRepository<YourEntityClass, String>{
}
(ii): JPA repository
#Repository public interface PostGresRepo extends JpaRepository<TestEntity,Long> {}
The Problem i have resulted out of this tutorial.
My Problem is that i always run in the issue that my user is read out of the database but i don't get authenticated. On the view it always shows the error message "Invalid Username or Password". My Console-output shows no errors. When i debugged through my authentication process there were no unclear behaviours where the error could come from.
In my pom.xml i used the following dependencies.
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
My CustomUserDetailsService.java looks like this.
#Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
private final UserRolesRepository userRolesRepository;
#Autowired
public CustomUserDetailsService(UserRepository userRepository,
UserRolesRepository userRolesRepository) {
this.userRepository = userRepository;
this.userRolesRepository = userRolesRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUserName(username);
if (user == null) {
throw new UsernameNotFoundException("No user present with username " + username);
}
else {
List<String> userRoles = userRolesRepository.findRoleByUserName(username);
return new CustomUserDetails(user, userRoles);
}
}
}
CustomUserDetails.java
public class CustomUserDetails extends User implements UserDetails {
private static final long serialVersionUID = 1L;
private List<String> userRoles;
public CustomUserDetails(User user, List<String> userRoles) {
super(user);
this.userRoles = userRoles;
}
#Override
public Collection< ? extends GrantedAuthority> getAuthorities() {
String roles = StringUtils.collectionToCommaDelimitedString(userRoles);
return AuthorityUtils.commaSeparatedStringToAuthorityList(roles);
}
#Override
public boolean isAccountNonExpired() {
return false;
}
#Override
public boolean isAccountNonLocked() {
return false;
}
#Override
public boolean isCredentialsNonExpired() {
return false;
}
}
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home", "/images/**", "/css/**", "/js/**", "/loadEvents")
.permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login")
.permitAll().and().logout().permitAll();
}
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordencoder() {
return new BCryptPasswordEncoder();
}
}
As i mentioned before i don't think that the error occures on the database. I used the database scheme out of the tutorial. I also used User.java UserRole.java and the two repositories out of the tutorial.
My Application.java looks like this.
#SpringBootApplication
#EnableJpaRepositories(basePackages = "<package>")
#EntityScan(basePackages = "<package>")
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
Update 1: Link to Git Project
https://github.com/pStuetz/Speeddating4SO/tree/master
You maybe have to Edit the src/main/resources/application.properties to support your database. I included the sql script which i used to create my database tables.
I've enabled trace logging in application.properties by adding this row
logging.level.=TRACE
and saw the error message
org.springframework.security.authentication.LockedException: User account is locked
in the console.
Your custom user details class de.dhbw.stuttgart.speeddating.userhandling.service.impl.CustomUserDetails returns "false" from methods "isAccountNonExpired", "isAccountNonLocked" and "isCredentialsNonExpired". I guess the methods should return the value of the property "enabled" from the class de.dhbw.stuttgart.speeddating.userhandling.service.User.
After changing all those "false" to "true", the login procedure started to work as expected.
I have entities with bidirectional mapping to each other. Calling REST Http.GET request to get all records from db, I am receiving StackOverflowException due to infinite recursion. I was trying to use #JsonIgnore, #JsonBackReference together with #JsonManageReference and #JsonIdentityInfo in different combinations, but with no positive result. I am still receiving the error.
Spring Boot loads me jackson in version 2.6.6.
Here is my BaseEntity:
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue
private Long id;
private String createdBy;
private Date createdOn;
private String modifiedBy;
private Date modifiedOn;
public String description;
public BaseEntity() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public String getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(String modifiedBy) {
this.modifiedBy = modifiedBy;
}
public Date getModifiedOn() {
return modifiedOn;
}
public void setModifiedOn(Date modifiedOn) {
this.modifiedOn = modifiedOn;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
First Entity class:
#Entity
public class Entry extends BaseEntity{
private Date businessOperationDate;
#ManyToOne
private Version version;
#ManyToOne
private Status status;
#ManyToOne
#JsonManagedReference
private Account account;
public Entry() {
}
public Date getBusinessOperationDate() {
return businessOperationDate;
}
public void setBusinessOperationDate(Date businessOperationDate) {
this.businessOperationDate = businessOperationDate;
}
public Version getVersion() {
return version;
}
public void setVersion(Version version) {
this.version = version;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
and the second one:
#Entity
public class Account extends BaseEntity{
private String number;
#OneToMany(mappedBy = "account", fetch = FetchType.EAGER)
#JsonBackReference
private List<Entry> entries;
#ManyToMany(mappedBy = "accounts")
private List<Project> projects;
public Account() {
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public List<Entry> getEntries() {
return entries;
}
public void setEntries(List<Entry> entries) {
this.entries = entries;
}
public List<Project> getProjects() {
return projects;
}
public void setProjects(List<Project> projects) {
this.projects = projects;
}
}
Here you can find part of result received from Http.GET request:
[{"id":1,"createdBy":null,"createdOn":null,"modifiedBy":null,"modifiedOn":null,"description":"pierwszy zapis","businessOperationDate":null,"version":null,"status":null,"account":{"id":1,"createdBy":null,"createdOn":null,"modifiedBy":null,"modifiedOn":null,"description":"pierwszy projekt","number":null,"entries":
[{"id":1,"createdBy":null,"createdOn":null,"modifiedBy":null,"modifiedOn":null,"description":"pierwszy zapis","businessOperationDate":null,"version":null,"status":null,"account":{"id":1,"createdBy":null,"createdOn":null,"modifiedBy":null,"modifiedOn":null,"description":"pierwszy projekt","number":null,"entries":
[{"id":1,"createdBy":null,"createdOn":null,"modifiedBy":null,"modifiedOn":null,"description":"pierwszy zapis","{"timestamp":1468778765328,"status":200,"error":"OK","exception":"org.springframework.http.converter.HttpMessageNotWritableException","message":
"Could not write content: Infinite recursion (StackOverflowError) (through reference chain: com.test.test2.core.dto.AccountDto[\"entries\"]->
java.util.ArrayList[0]->com.test.test2.core.dto.EntryDto[\"account\"]->com.test.test2.core.dto.AccountDto[\"entries\"]->
java.util.ArrayList[0]->com.test.test2.core.dto.EntryDto[\"account\"]->com.test.test2.core.dto.AccountDto[\"entries\"]->java.util.ArrayList[0]->com.test.test2.core.dto.EntryDto[\"account\"]->com.test.test2.core.dto.AccountDto[\"entries\"]->
java.util.ArrayList[0]->com.test.test2.core.dto.EntryDto[\"account\"]-
pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test2</name>
<description>test2</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-security</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
<version>9.4-1201-jdbc41</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- model mapper -->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.4.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Please advise, what I am doing wrong. I wish to receive in a result only one level, e.g. calling getAll() for entry, I wish to receive all entries with information which account is related, and in opposite once calling getAll() for account.
i search more times for this error,but i can meet anything i get this error case and i correct it by adding the annotation #JsonIgnore in some relation mapping,
this is example
#ManyToMany(mappedBy = "accounts")
#JsonIgnore
private List<Project> projects;
I facing issue when i am getting id after saving the claimDetail object then to get the id of that saved object it is coming 0 . Actually I want get that saved object Id .But it not coming. I did not work with JPA. I have created a Spring Boot application for scheduling .
Here is my ClaimDetails.java entity class:
#Entity
#Table(name = "claimtrans")
public class ClaimTrans {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
claimDetail.setActive(1);
claimDetail.setVersion(new Long(1));
claimDetail.setCreatedBy(new Long(1));
claimDetail.setCreatedDate(new Date());
claimDetailService.saveClaimDetail(claimDetail);
int temp =claimDetail.getID()
temp is 0;
Here is my JpaRepositoryFactory.java:
#Service
public class ClaimDetailService {
private JpaRepositoryFactory jpaRepositoryFactory;
#Autowired
public ClaimDetailService(JpaRepositoryFactory jpaRepositoryFactory) {
this.jpaRepositoryFactory = jpaRepositoryFactory;
}
#Transactional
public void saveClaimDetail(ClaimDetail claimDetail) {
JpaRepository<ClaimDetail, Long> mailAuditLogLongJpaRepository = jpaRepositoryFactory.getRepository(ClaimDetail.class);
mailAuditLogLongJpaRepository.save(claimDetail);
}
public List<ClaimDetail> getAllClaimDetail() {
JpaRepository<ClaimDetail, Long> mailAuditLogLongJpaRepository = jpaRepositoryFactory.getRepository(ClaimDetail.class);
return mailAuditLogLongJpaRepository.findAll();
}
}
Here is my JPA Factory.
#Component
public class JpaRepositoryFactory {
#PersistenceContext
private EntityManager entityManager;
public <T> T getRepository(Class clazz) {
notNull(clazz);
notNull(entityManager);
T crudRepository = (T) new SimpleJpaRepository(clazz, entityManager);
return crudRepository;
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>org.sam.application.Application</start-class>
<java.version>1.6</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
</dependency>
Anyone can help me please how to fix this issue ?
Thanks
Sitansu
The JPA spec doesn't guarantee that the provided entity object will be updated after saving it. To get the saved JPA entity you have to use the return value of the save() method. For example, your service could be changed this way:
#Service
public class ClaimDetailService {
...
#Transactional
public ClaimDetail saveClaimDetail(ClaimDetail claimDetail) {
JpaRepository<ClaimDetail, Long> mailAuditLogLongJpaRepository = jpaRepositoryFactory.getRepository(ClaimDetail.class);
return mailAuditLogLongJpaRepository.save(claimDetail);
}
...
}
And your sample code would be:
claimDetail.setActive(1);
claimDetail.setVersion(new Long(1));
claimDetail.setCreatedBy(new Long(1));
claimDetail.setCreatedDate(new Date());
ClaimDetail savedClaimDetail = claimDetailService.saveClaimDetail(claimDetail);
int temp = savedClaimDetail.getID()
Also, although not directly related to your problem, you don't need to create the Spring Data repositories the way you have done it. Just create your own interface extending JPARepository.
Write a configuration class and do something like this. Use JpaRepository
#Configuration
public class ClaimDetailService {
public interface ClaimDetailRepository extends JpaRepository<Claimtrans, String>{
ClaimDetail findById(String id);
}
#Autowired
ClaimDetailRepository claimDetailRepository;
#Autowired
public void save(){
ClaimTrans claimDetail=new ClaimTrans();
claimDetail.setId(UUID.randomUUID.toString());
claimDetail.setActive(1);
claimDetail.setVersion(new Long(1));
claimDetail.setCreatedBy(new Long(1));
claimDetail.setCreatedDate(new Date());
claimDetailRepository.save(claimDetail);
int temp =claimDetailRepository.findById(claimDetail.getId());
}
}
I am beginning with REST techniologies, and I choose Spring 3.2 and Jackson 2.2 . I have small question. I created REST API and it looks like this:
#Controller
public class WorkersController {
#Autowired
public DatabaseService dbService;
#ResponseBody
#RequestMapping(value="/workers", method = RequestMethod.GET, produces = "application/json")
public ArrayList<Worker> getAllWorkersFromDatabase() {
}
#ResponseBody
#RequestMapping(value="/workers/new", method = RequestMethod.POST, produces = "application/json", consumes="application/json")
public String saveWorker(#RequestBody final WorkerDTO workerDto) {
}
#ResponseBody
#RequestMapping(value="/workers/{workerid}", method = RequestMethod.GET, produces = "application/json")
public Worker getWOrkerByDatabaseId(#PathVariable Integer workerid) {
}
#ResponseBody
#RequestMapping(value="/workers/{workerid}/edit", method = RequestMethod.PUT, produces = "application/json")
public String editWorker(#PathVariable Integer workerid, #RequestBody Worker worker) {
}
}
When I make HTTP GET all is ok but I have problem with POST. When I am calling saveWorker() method I get:
The server refused this request because the request entity is in a format not supported by the requested resource for the requested method
I imported required libraries:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
I think the main problem is in configuration files and #RequestBody cant map JSON to DTO. It is my Configuration:
#Configuration
#ComponentScan(basePackages = "org.schedule.service")
#EnableWebMvc
#Import(DatabaseSpringConfig.class)
public class ServiceSpringConfig extends WebMvcConfigurationSupport{
#Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
List<MediaType> jsonTypes = new ArrayList<>(jsonConverter.getSupportedMediaTypes());
jsonTypes.add(MediaType.TEXT_PLAIN);
jsonTypes.add(MediaType.APPLICATION_JSON);
jsonConverter.setSupportedMediaTypes(jsonTypes);
converters.add(jsonConverter);
}
}
My DTO:
public class WorkerDTO implements Serializable {
private static final long serialVersionUID = 1L;
public String name;
public String surname;
public WorkerDTO() {
}
}
Json:
{
"name": "asdssss",
"surname": "asdssssss"
}
And http call:
localhost:8080/Schedule-service/workers/new?Content-type=application/json
Thanks for all replies.
The request
localhost:8080/Schedule-service/workers/new?Content-type=application/json
has a request parameter with name Content-Type and value application/json.
HttpMessageConverter classes, and MappingJackson2HttpMessageConverter in particular, don't look for request parameters, they look for headers.
You need to specify a Content-Type header for your request.