Propagating foreign key with Spring Data - mysql

I am developing an Spring Boot app based on Spring Data Rest(which uses Hibernate underneath) and mySQL database. This app is incapable to populate the foreign keys of the referenced entries(because I expect Hibernate does it for me).
Entities:
#Entity
public class Producto {
private Integer id;
private String nombre;
private List<Formato> listaFormatos;
public Producto() {
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
#OneToMany(mappedBy = "producto", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<Formato> getListaFormatos() {
return listaFormatos;
}
public void setListaFormatos(List<Formato> listaFormatos) {
this.listaFormatos = listaFormatos;
}
}
#Entity
public class Formato {
private Integer id;
private Integer cantidad;
private String unidadMedida;
private Producto producto;
public Formato() {
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne
#JoinColumn(name = "producto_id", referencedColumnName = "id")
public Producto getProducto() {
return producto;
}
public void setProducto(Producto producto) {
this.producto = producto;
}
public Integer getCantidad() {
return cantidad;
}
public void setCantidad(Integer cantidad) {
this.cantidad = cantidad;
}
public String getUnidadMedida() {
return unidadMedida;
}
public void setUnidadMedida(String unidadMedida) {
this.unidadMedida = unidadMedida;
}
}
Repository:
public interface ProductoRepository extends CrudRepository<Producto, Integer> {
}
application.properties
spring.datasource.url = jdbc:mysql://localhost:3306/x1
spring.datasource.username = x2
spring.datasource.password = x3
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=create-drop
pom.xml
<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-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</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-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Let's say that the request I am sending in JSON format looks like this:
{"nombre": "x",
"listaFormatos": [
{"cantidad": 1,
"unidadMedida":"kg"},
{"cantidad": 2,
"unidadMedida":"g"}
]
}
The output of all this is that I persist an 'producto' and 2 'formato' without foreign key. Because of that, I believe I cannot bring a producto with its formats
Does anyone know why the foreign key is not being propagated?

Empty FKs usually happening when you are not setting the back references.
Consider the following:
Parent p = new Parent();
...
Child c = new Child();
...
p.setChild(c);
c.setParent(p); // this is the line you are probably missing
Of course, you can put this logic into the Parent#setChild method as well.

Related

Can't Configure Apache Shiro with MySQL, SHA256 Password Hashing Algorithm, Salting in Base64 String

I am trying to configure Apache Shiro using shiro.ini in order to authenticate users against MySQL Database where all credentials are saved. Passwords are hashed using sha256 algorithm and a salt per user is used and saved/recovered from MySQL database. I would like to avoid creating custom Realm and custom SaltedAuthentificationInfo which i believe is possible through shiro.ini proper configuration
Or not?? Is this possible?
Can i avoid using custom Realm and SaltedAuthentificationInfo??
To register users i implemented the following function
#POST
#Path("new")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String create(User requestBody) {
System.err.println("NEW User");
User user = new User();
user.setFirstName(requestBody.getFirstName());
user.setLastName(requestBody.getLastName());
user.setEmail(requestBody.getEmail());
// Do Something With Salt Per User Random Generation or Something like it
//================================================================================================================
RandomNumberGenerator rng = new SecureRandomNumberGenerator();
String salt = rng.nextBytes().toBase64();
String hashedPasswordBase64 = new Sha256Hash(requestBody.getPassword(), salt, 1024).toBase64();
user.setSalt(salt);
user.setPassword(hashedPasswordBase64);
boolean result = userDAO.persist(user);
userDAO.closeEntityManager();
if (result) {
return ReturnResults.results(new ArrayList<User>(asList(user)));
}
return "{}";
}
My shiro.ini:
[main]
ds = com.mysql.cj.jdbc.MysqlDataSource
ds.serverName = 127.0.0.1
ds.user = **********
ds.password = **********
ds.databaseName = **********
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource = $ds
jdbcRealm.permissionsLookupEnabled = false
jdbcRealm.authenticationQuery = "SELECT password, salt FROM User WHERE email = ?"
jdbcRealm.userRolesQuery = "SELECT role_name FROM UserRole WHERE email = ?"
# jdbcRealm.permissionsQuery = "SELECT permission FROM RolesPermissions WHERE role_name = ?"
authc.usernameParam = email
authc.passwordParam = password
authc.failureKeyAttribute = shiroLoginFailure
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
#credentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.storedCredentialsHexEncoded = false
# credentialsMatcher.hashAlgorithmName = SHA-256
credentialsMatcher.hashIterations = 1024
jdbcRealm.credentialsMatcher = $credentialsMatcher
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordMatcher.passwordService = $passwordService
shiro.loginUrl = /authentication/login
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionIdCookieEnabled = false
ssl.enabled = false
securityManager.realms = $jdbcRealm
strategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $strategy
[users]
[roles]
[urls]
/authentication/login = authc
/authentication/logout = logout
/doctors/* = authc
/users/new = anon
/users/details/* = anon
/users/* = authc
My DB Schema:
My Implemented Transfer Objects:
User
package gr.histopath.platform.model.TransferObjects;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.util.Objects;
#Entity
#Cacheable
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "EntityCache")
public class User {
private long id;
private String email;
private String firstName;
private String lastName;
private String password;
private String salt;
private boolean activated;
#Id
#Column(name = "id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Basic
#Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Basic
#Column(name = "firstName")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Basic
#Column(name = "lastName")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Basic
#Column(name = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Basic
#Column(name = "salt")
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
#Basic
#Column(name = "activated")
public boolean getActivated() {
return this.activated;
}
public void setActivated(boolean activated){
this.activated = activated;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id &&
Objects.equals(email, user.email) &&
Objects.equals(firstName, user.firstName) &&
Objects.equals(lastName, user.lastName) &&
Objects.equals(password, user.password) &&
Objects.equals(salt, user.salt) &&
Objects.equals(activated, user.activated);
}
#Override
public int hashCode() {
return Objects.hash(id, email, firstName, lastName, password, salt, activated);
}
}
UserRole Transfer Object:
package gr.histopath.platform.model.TransferObjects;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.util.Objects;
#Entity
#Cacheable
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "EntityCache")
public class UserRole {
private int id;
private String roleName;
private String email;
#Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "roleName")
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
#Basic
#Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserRole userRole = (UserRole) o;
return id == userRole.id &&
Objects.equals(email, userRole.email) &&
Objects.equals(roleName, userRole.roleName) &&
Objects.equals(email, userRole.email);
}
#Override
public int hashCode() {
return Objects.hash(id, email, roleName);
}
}
Finally my login() function:
#POST
#Path("login")
#Produces(MediaType.TEXT_PLAIN)
public boolean login(Authentication authData) {
System.out.println("Param email: " + authData.getEmail());
System.out.println("Param password: " + authData.getPassword());
UsernamePasswordToken token = new UsernamePasswordToken(authData.getEmail(), new Sha256Hash(authData.getPassword()).toBase64());
if (!subject.isAuthenticated()) {
try {
System.out.println("Trying to authenticate with token");
subject.login(token);
System.out.println("User [" + subject.getPrincipal().toString() + "] logged in successfully.");
return true;
} catch (UnknownAccountException uae) {
log.error("Username Not Found!", uae);
System.out.println("Username Not Found!");
} catch (IncorrectCredentialsException ice) {
log.error("Invalid Credentials!", ice);
System.out.println("Invalid Credentials!");
} catch (LockedAccountException lae) {
log.error("Your Account is Locked!", lae);
System.out.println("Your Account is Locked!");
} catch (AuthenticationException ae) {
log.error("Unexpected Error!", ae);
System.err.println("Unexpected Error!");
} catch (Exception ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
}
} else {
return true;
}
return false;
}
After calling subject.login(token) i get shiro error "Unexpected Error!"
Stack Trace:
Unexpected Error!
org.apache.shiro.authc.AuthenticationException: There was a SQL error while authenticating user [mixtou#gmail.com]
at org.apache.shiro.realm.jdbc.JdbcRealm.doGetAuthenticationInfo(JdbcRealm.java:254)
at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:568)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:267)
at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)
at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:270)
at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:256)
at gr.histopath.platform.controllers.authentication.AuthenticationController.login(AuthenticationController.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:76)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:148)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:191)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:243)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:277)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:268)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:268)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:491)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:764)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1388)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:545)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:513)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:505)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:479)
at com.mysql.cj.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3246)
at com.mysql.cj.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3230)
at com.mysql.cj.jdbc.PreparedStatement.setString(PreparedStatement.java:4025)
at org.apache.shiro.realm.jdbc.JdbcRealm.getPasswordForUser(JdbcRealm.java:281)
at org.apache.shiro.realm.jdbc.JdbcRealm.doGetAuthenticationInfo(JdbcRealm.java:221)
... 70 more
Any Ideas what i am missing or doing wrong??
Is my shiro.ini ok??
Is this possible without implementing custom classes for Realm and SaltedAuthentificationInfo ?? Most of the examples i have seen so far are implementing custom classes. However i haven't found any recent example using shiro 1.4
Any advice is very appreciated. I am banging my head two days now...
I don't know if there is any problem with dependencies, so i upload my pom.xml also.
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>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<groupId>gr.histopath.platform</groupId>
<artifactId>HistopathPlatform</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1</version>
</dependency>
<!-- Logging API + implementation: -->
<!--<dependency>-->
<!--<groupId>org.slf4j</groupId>-->
<!--<artifactId>slf4j-simple</artifactId>-->
<!--<version>1.7.25</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.6.4</version>
<scope>runtime</scope>
</dependency>
<!--https://mvnrepository.com/artifact/org.apache.shiro/shiro-core-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-lang -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-lang</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-crypto-cipher -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-crypto-cipher</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-crypto-hash -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-crypto-hash</artifactId>
<version>1.4.0</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.secnod.shiro</groupId>-->
<!--<artifactId>shiro-jersey</artifactId>-->
<!--<version>0.2.0</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.11.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>5.0.4.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.3.3.Final</version>
</dependency>
<!--2nd Level Cache-->
<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.5</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.3.3.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-jpamodelgen -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.3.Final</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>io</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdfa</artifactId>
<version>7.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
Could the problem be in my user registration code or with the mysql jdbc driver or with web.xml??
It is absolutely possible and is meant for this purpose. From what I see you are heading towards the right direction; However I see that you are using queries like
SELECT password, salt FROM User WHERE email = ?
and SELECT role_name FROM UserRole WHERE email = ?
for authentication and roles. Can you confirm that User and UserRole are your table names? Note that using JDBC realm connects to your database using the specified datasource and performs SQL queries regardless of any persistance frameworks you have implemented.
Also, when you configure shiro.loginUrl = /authentication/login and /authentication/login = authc the action of the login form is intended to be empty. Hence no controller is required
#POST
#Path("login")
#Produces(MediaType.TEXT_PLAIN)
public boolean login(Authentication authData) {.....}
to handle the security. The framework handles the part for you.

Spring REST Controller returns empty JSON. Iterable data structure. Why?

I realize a very similar question was asked and closed because it wasn't specific enough and didn't specify outcomes. Closed Off Topic
Problem: JSON being returned from REST controller is empty. Verified data exists and is in the Iterable.
Expected Outcome: A JSON Array containing objects would be returned.
<?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.codeexcursion</groupId>
<organization>
<name>Chris Lynch</name>
</organization>
<version>1.00.000</version>
<artifactId>work-tracking</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<name>Work Tracking</name>
<inceptionYear>2017</inceptionYear>
<developers>
<developer>
<id />
<name>Chris Lynch</name>
<email>chrislynch42#yahoo.com</email>
<timezone>-4</timezone>
<roles>
<role>Chief cook and bottle washer.</role>
</roles>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.10.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.13.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.codeexcursion.Application</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Entity
//Package and import Omitted
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long parentId;
private String title;
private String description;
protected Category() {
}
public Category(final String title, String description) {
this(0L, title, description);
}
public Category(Long parentId, final String title, String description) {
if (parentId == null) {
parentId = 0L;
}
if (title == null || title.trim().isEmpty()) {
throw new IllegalArgumentException("Title may not be null or empty.");
}
if (description == null) {
description = "";
}
this.parentId = parentId;
this.title = title;
this.description = description;
}
#Override
public String toString() {
return "id = " + id + "; parentId=" + parentId + "; title=" + title + "; description=" + description;
}
}
Resource
//Package and import Omitted
#Repository
public interface CategoryCRUD extends CrudRepository<Category, Long> {
List<Category> findByTitle(String title);
}
Rest Controller
//Package and import Omitted
#RestController
#RequestMapping("/categories")
public class CategoryController {
#Autowired
private CategoryCRUD categoryCRUD;
#RequestMapping(value = "", method = RequestMethod.GET)
public #ResponseBody Iterable<Category> list() {
System.out.println("findAll");
categoryCRUD.findAll().forEach((category) -> {
System.out.println("category=" + category);
});
return categoryCRUD.findAll();
}
private List<Category> findAll() {
final Iterable<Category> data = categoryCRUD.findAll();
List<Category> returnList = new ArrayList<>();
data.forEach(returnList::add);
return returnList;
}
}
I found an answer that was hinted on the closed post but wasn't detailed. I needed to add getters to my entity. I expected JPA/Spring to automagically add the getters and setters. The below fixed my problem.
Entity
//Package and imports omitted
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long parentId;
private String title;
private String description;
protected Category() {
}
public Category(final String title, String description) {
this(0L, title, description);
}
public Category(Long parentId, final String title, String description) {
if (parentId == null) {
parentId = 0L;
}
if (title == null || title.trim().isEmpty()) {
throw new IllegalArgumentException("Title may not be null or empty.");
}
if (description == null) {
description = "";
}
this.parentId = parentId;
this.title = title;
this.description = description;
}
#Override
public String toString() {
return "id = " + id + "; parentId=" + parentId + "; title=" + title + "; description=" + description;
}
public Long getId() {
return id;
}
public Long getParentId() {
return parentId;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
}
Better answers are welcome.
In my case, the getters to the fields of the entity were not public.
Making them public fixed the issue for me.
You have to include the lombok dependency in your pom.xml file and you have to setup the lombok jar in the IDE you are using (Can be Intellij or Eclipse). if you want to use the annotations #Data, it automatically generates the getters, setters and toString() method inside a Java Bean or Pojo class.
You can use #Getter, #Setter, #AllArgsConstructor, #NoArgsConstructor javadoc annotation from lombok will generate the getters and setters and constructors for your fields.
Please have a look at this http://www.baeldung.com/intro-to-project-lombok for more information.
Thanks!

How can I return JSON object list with Jersey/Jackson

I am using Jersey/Jackson for return object to JSON.
I can return it successfully for single object but I can't return for list.
How do i return list object serialize to JSON
This is My Example
dependencies like this :
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.19</version>
</dependency>
</dependencies>
My model Like this :
public class Person {
private String name;
private String surname;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, String surname, int age) {
super();
this.name = name;
this.surname = surname;
this.age = age;
}
public Person() {
super();
}
#Override
public String toString() {
return "Person [name="+ name +", surname="+ surname +", age="+ age +"]";
}
My Service Like this :
#Path("/getperson")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getPerson(){
Person person = new Person(name, surname, age);
return person;
}
#Path("/getpersons")
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Person> getPersons(){
Person p1 = new Person("gosling", "james", 55);
Person p2 = new Person("torvalds", "linus", 48);
Person p3 = new Person("riche", "dennis", 60);
List<Person> persons = new ArrayList<Person>();
persons.add(p1);
persons.add(p2);
persons.add(p3);
return persons;
}
getPerson() work well but getpersons() returning empty.
In my scenario, I am using glassfish jersey dependencies :
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
and lists do get returned almost as I would like with 0 configuration or mapping.
I don't see any particular issue in your code.

Jackson FasterXML : How does Spring know how to json object?

I am currently following this tutorial about Spring MVC and REST service. It is a simple hello world project.
There is something I don't understand. In the pom.xml we set jackson dependency but it is never configurated. How does Spring know how to json object ?
Here is samples of code :
pom xml (dependencies) :
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.library}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson.library}</version>
</dependency>
</dependencies>
AppConfiguration :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "package.to.scan")
public class AppConfiguration {
}
AppInitializer :
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfiguration.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
AppController :
#RestController
public class AppController {
#RequestMapping("/")
public String welcome() {
return "Welcome to RestTemplate Example.";
}
#RequestMapping("/hello/{player}")
public Message message(#PathVariable String player) {
Message msg = new Message(player, "Hello " + player);
return msg;
}
}
Model :
public class Message {
String name;
String text;
public Message(){
}
public Message(String name, String text) {
this.name = name;
this.text = text;
}
public String getName() {
return name;
}
public String getText() {
return text;
}
}
Spring has a default set of HttpMessageConverters, one of them being MappingJackson2HttpMessageConverter, which is used if the content type is json and if Jackson is available in the classpath.

Spring Boot - entity to json - recursive

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;