Jackson #JsonView doesn't works as expected - json

I'm using Jackson JSON 1.9.12 with SpringMVC. I've created a dto with JSON fields. I want two profiles of same dto with different JSON fields, so I created two interfaces and I've annotated fields with #JsonView annotation.
class Views {
static class Public {}
static class ExtendedPublic {}
...
}
public class Thing {
#JsonView(Views.Public.class) Integer id;
#JsonView(Views.ExtendPublic.class) String name;
}
In controller
#RequestMapping(value = "/thing/{id}")
public void getThing(#PathVariable final String id, HttpServletResponse response) {
Thing thing = new Thing();
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writerWithView(Views.Public.class).writeValueAsString(thing);
LOG.debug("JSON: {}", json);
}
I expect JSON to contain only "id" field, but it always contains all fields.
Any ideas?

The following code is tested with Spring 3.2.0 and Jackson 1.9.12 which simply returns {id: 1} and not the extended {name: "name"} since it is using the .writerWithView(Views.Public.class). Switching to Views.ExtendPublic.class will result in {"id":1,"name":"name"}
Edit: Adding all project files for a complete solution, making this a better answer than my other one on Using #JsonView with Spring MVC
DemoController.java
package com.demo.app;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.codehaus.jackson.map.annotate.JsonView;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Controller
public class DemoController {
private final ObjectMapper objectMapper = new ObjectMapper();
#RequestMapping(value="/jsonOutput")
#ResponseBody
public String myObject(HttpServletResponse response) throws IOException {
ObjectWriter objectWriter = objectMapper.writerWithView(Views.Public.class);
return objectWriter.writeValueAsString(new MyObject());
}
public static class Views {
static class Public {}
static class ExtendPublic extends Public {}
}
public class MyObject {
#JsonView(Views.Public.class) Integer id = 1;
#JsonView(Views.ExtendPublic.class) String name = "name";
}
}
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"/>
Initializer.java
package com.demo.app.spring;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.*;
public class Initializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(AppConfig.class);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(mvcContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
}
}
AppConfig.java
package com.demo.app.spring;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.demo.app")
public class AppConfig {
}
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>
<groupId>com.demo</groupId>
<artifactId>app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>${project.artifactId}</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.2.0.RELEASE</spring.version>
<jetty.plugin.version>8.1.7.v20120910</jetty.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.plugin.version}</version>
<configuration>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
</project>
In the following structure:
pom.xml
src
|- main
|- java
| |- com
| |- demo
| |- app
| |- controller/DemoController.java
| |- spring/AppConfig.java, Initializer.java
|- webapp
|- WEB-INF/web.xml

Related

spring boot + JPA + mysql, unable to retrieve result set

i am new to spring boot, having basic knowledge of java. i am trying to build a micro-service to retrieve data from mySQL database. below are the code details.
i am able to retrieve data from the same table using standalone JDBC class. request to help.
- Entity class
package com.studentProject.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.springframework.stereotype.Component;
#Entity
#Component
#Table(name="students", schema="test_schema")
public class StudentEntity implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
private Integer id;
#Column(name="name")
private String name;
#Column(name="course")
private String course;
#Column(name="country")
private String country;
#Column(name="phone")
private String phone;
public StudentEntity(Integer id, String name, String course, String country, String phone) {
super();
this.id = id;
this.name = name;
this.course = course;
this.country = country;
this.phone = phone;
}
public StudentEntity() {
super();
// TODO Auto-generated constructor stub
}
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 getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
-Repository Class
package com.studentProject.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.studentProject.entity.StudentEntity;
#Repository
public interface StudentRepository extends CrudRepository<StudentEntity, Integer> {
StudentEntity findByName(String name);
StudentEntity findByCourse(String course);
}
-Controller class
package com.studentProject.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.studentProject.entity.StudentEntity;
import com.studentProject.repository.StudentRepository;
#RestController
public class StudentController {
#Autowired
private StudentRepository studentRepository;
#Autowired
List<StudentEntity> studentList;
public StudentController(StudentRepository studentRepository, StudentEntity studentEntity,
List<StudentEntity> studentList) {
super();
this.studentRepository = studentRepository;
this.studentList = studentList;
}
#GetMapping("/getStudentDetails")
public Iterable<StudentEntity> getAllStudents(){
return studentRepository.findAll();
}
#GetMapping("/getStudentDetails/getByName")
public StudentEntity findByName(#RequestParam(value="name") String name) {
return studentRepository.findByName(name);
}
#GetMapping("/getStudentDetails/getById/{id}")
public Optional<StudentEntity> findById(#PathVariable(value="id") Integer id) {
return studentRepository.findById(id);
}
#GetMapping("/getStudentDetails/welcome")
public String welcome() {
return "hi brother welcome";
}
}
-Properties File
server.port = 8080
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.data.jpa.repositories.enabled=true
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = none
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
--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.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.StudentProject</groupId>
<artifactId>StudentProject-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>StudentProject-1</name>
<description>Demo project for Spring Boot</description>
<properties>
<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-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
-main application
package com.studentProject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class StudentProject1Application {
public static void main(String[] args) {
SpringApplication.run(StudentProject1Application.class, args);
}
}
-mysql table details
schema=test_schema and table=students
error details
From the error log
Caused by: java.sql.SQLException: No database selected
it is clear that spring is not able to find database so select database by following below.
change the spring.datasource.url value to below by adding database name.
spring.datasource.url = jdbc:mysql://localhost:3306/test_schema
Caused by: java.sql.SQLException: No database selected at
This tells that you must select the database name, so you must add it in your config. I saw you already got an answer!
spring.datasource.url = jdbc:mysql://localhost:3306/YOUR_DB_SCHEMA

SessionFactory not autowired even with Beans provided

Integrating spring boot and hibernate but there is an issue with SessionFactory autowiring as it is saying that beans are not provided but #Bean is provided in the Configuration class.
Please have a look at the code.
Dao layer was not provided yet as i'm having issue with SessionFactory autowiring.
MAIN APPLICATION CLASS
package com.ctechm.ctec;
import java.util.Arrays;
import org.hibernate.SessionFactory;
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.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.repository.CrudRepository;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import com.ctechm.ctec.service.ServiceImpl;
#SpringBootApplication
public class CtecApplication implements CommandLineRunner{
#Autowired
private ApplicationContext appContext;
#Autowired
Text text;
#Autowired
ServiceImpl serviceImpl;
#Autowired
SessionFactory sessionFactory;
public static void main(String[] args) {
SpringApplication.run(CtecApplication.class);
}
}
#Autowired Annotations are provided in the above code and their #Bean is defined in the Configuration class.It is working fine for all Autowirings except for SessionFactory.
CONFIGURATION CLASS
package com.ctechm.ctec;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.context.annotation.Configuration;
#Configuration
public class Configuration {
#Bean
public Text text() {
return new Text();
}
#Bean
public Text texter(){
return new Text();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/scm");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
Properties properties = new Properties();
LocalSessionFactoryBean bean=new LocalSessionFactoryBean();
bean.setDataSource(dataSource());
properties.setProperty("hibernate.connection.url","jdbc:mysql://localhost:3306/scm"); properties.setProperty("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.connection.username","root");
properties.setProperty("hibernate.connection.password","password");
bean.setHibernateProperties(properties);
return bean;
}
}
Service class
package com.ctechm.ctec.service;
import java.lang.annotation.Annotation;
import com.ctechm.ctec.service.Service;
#Service
public class ServiceImpl implements Service {
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/scm
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.properties.hibernate.format_sql = true
spring.jpa.hibernate.ddl-auto=none
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>
<groupId>com.ctechm</groupId>
<artifactId>ctec</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ctec</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<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-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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
When ever i start the console getting error like this
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jpaContext': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.Set<javax.persistence.EntityManager>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:732) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:197) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1276) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1133) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:503) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at com.ctechm.ctec.CtecApplication.main(CtecApplication.java:33) [classes/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.Set<javax.persistence.EntityManager>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1509) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:818) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:724) ~[spring-beans-5.0.7.RELEASE.jar:5.0.7.RELEASE]
... 19 common frames omitted
Please have a look and suggest me what changes need to be done.
One thing was when i remove bean and autowiring of sessionFactory everything was working fine.I tried from all the posts in stackoverflow but was not able to figure out the solution.
From the code you posted it is not clear what you want to achieve here.
Using spring-boot and spring-data you basically can start the app with minimum configuration.
In your case you can skip the Configuration.java and configure the database access using the Common Spring Boot properties which you can add directly in the application.properties file.
application.properties
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/scm?useSSL=false
spring.datasource.username = spring-test
spring.datasource.password = root
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
Autowiring SessionFactory is not needed, instead you can add a Repository interface which will extend the JpaRepository interface. This interface already has definitions for the basic CRUD operations.
Here is an example of how that should look like.
CtecRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface CtecRepository extends JpaRepository<CtecEntity, String> {
List<CtecEntity> findByName(String name);
}
Than you can Inject your Repository to a Service class and from there you can work with the database.
CtecService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class CtecService {
#Autowired
private CtecRepository ctecRepository;
public void create() {
CtecEntity entity = new CtecEntity();
entity.setName("test name");
ctecRepository.save(entity);
}
public List<CtecEntity> getAllByName(String name) {
return ctecRepository.findByName(name);
}
}
CtecEntity.java
import javax.persistence.Id;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Table;
#Entity
#Table(name = "ctec")
public class CtecEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}

Getting "Bad SQL Grammar" error when trying to log-in using Spring Security

I am trying to build a simple Spring Boot CRUD application that also has login and signup options with spring boot security. I'm already working with a MySQL database and its working fine to persist the data for my application. I also have the signup working.
I'm having some problems with my Spring Security log-in implementation.
org.springframework.security.authentication.InternalAuthenticationServiceException: PreparedStatementCallback; bad SQL grammar [select username,authority from authorities where username = ?]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'cheesedb.authorities' doesn't exist
Obviously, I dont have an authorities class. I'm trying to authorize with email and password (I'll put in encryption once I have it working). I have two main models/classes, Cheese and Customer, but for this problem, I think Customer is the only model relevant.
Test2Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Test2Application {
public static void main(String[] args) {
SpringApplication.run(Test2Application.class, args);
}
}
SecurityConfig.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.sql.DataSource;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email as principal, password as credentials, true from customer where email=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable()
.authorizeRequests()
.antMatchers(
// "/cheese/index",
// "/cheese/",
"/**/webjars/**",
"/cheese/signup",
"/cheese/login",
// "/cheese/account",
// "/cheese/add",
// "/cheese/remove",
"/cheese/success").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/cheese/login")
.defaultSuccessUrl("/cheese/account")
.permitAll();
}
}
Customer
package com.example.demo.models;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
#Entity
public class Customer {
#NotNull
#Size(min=2, max=25)
private String name;
#GeneratedValue
#Id
private int accountNumber;
#NotNull
#Size(min=2, max=25)
private String password;
#NotNull
#Size(min=2, max=25)
#Email
private String email;
public Customer(String name, String password, String email) {
this.name = name;
this.password = password;
this.email = email;
}
public Customer() {}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAccountNumber() {
return accountNumber;
}
}
UserController
package com.example.demo.controllers;
import com.example.demo.models.Customer;
import com.example.demo.models.data.CustomerDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping("cheese")
public class UserController {
#Autowired
private CustomerDao customerDao;
#RequestMapping(value = "login")
public String loginPage(Model model) {
model.addAttribute("title", "Login Page");
return "cheese/login";
}
#RequestMapping(value = "account")
public String accountInfo(Model model) {
model.addAttribute("title", "Account Page");
return "cheese/account";
}
#GetMapping("signup")
public String displaySignUpForm(Model model) {
model.addAttribute("title", "Sign Up");
model.addAttribute("customer", new Customer());
return "cheese/signup";
}
#PostMapping(value = "signup")
public String processSignUp(Model model, #ModelAttribute Customer customer, Errors errors) {
if (errors.hasErrors()) {
return "cheese/signup";
}
customerDao.save(customer);
return "cheese/success";
}
}
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{fragments/main_layout}">
<head th:replace="fragments :: head"></head>
<body>
<nav th:replace="fragments :: navigation"></nav>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<div class="mx-auto" style="width: 400px;">
<br>
<h1 th:text="${title}">Log in</h1>
<br>
<br>
<form th:action="#{/cheese/login}" method="post">
<div class="form-group">
<label for="email" class="form-control-label">Email</label> <input
type="text" class="form-control" id="email" name="username" />
</div>
<div class="form-group">
<label for="password" class="form-control-label">Password</label> <input
type="password" class="form-control"
id="password" name="password"/>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
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>
<groupId>com.example</groupId>
<artifactId>test2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test2</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</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.webjars</groupId>
<artifactId>bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>

WRITE_DATES_AS_TIMESTAMPS not woking on Spring boot 1.3.5

I cannot get jackson to serialize dates correctly.
It always serialize as:
{"now":[2016,7,1,15,41,44,753]}
Instead of:
{"now":"2016-07-01T15:41:44.753"}
This is my source:
src/main/java/br/com/jjw/spring/jackson/bug/App.java
package br.com.jjw.spring.jackson.bug;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
src/main/java/br/com/jjw/spring/jackson/bug/MvcConfig.java
package br.com.jjw.spring.jackson.bug;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport {
#Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/public/");
}
}
src/main/java/br/com/jjw/spring/jackson/bug/MyRestController.java
package br.com.jjw.spring.jackson.bug;
import java.util.Collections;
import java.util.Map;
import org.joda.time.LocalDateTime;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MyRestController {
#RequestMapping("/get")
public Map<String, Object> get() {
return Collections.singletonMap("now", new LocalDateTime());
}
}
src/main/resources/application.properties
server.port=3000
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSS
pom.xml
<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>br.com.jjw</groupId>
<artifactId>spring-jackson-bug</artifactId>
<version>0.0.1-SNAPSHOT</version>
<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>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I found a solution, I just changed my MvcConfig to extends WebMvcConfigurerAdapter.
package br.com.jjw.spring.jackson.bug;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/public/");
}
}
To add, this post can help to understand why Difference between WebMvcConfigurationSupport and WebMvcConfigurerAdapter

JSON Mapping in my Spring MVC 3.2 Application Works for Only One of My Methods

I am working on a Spring 3.2 MVC application. It's setup fairly typically, but my problem is that I am getting a 406 status error when I attempt to return a JSON object from my controller methods.
The frustrating part is that I get that response from the server from all but one of my methods. The code I have included is a modified Spring MVC json example I found on the web. The sample's controller method with the path variable works as expected, but the additional methods that I added to the controller do not.
The only other change I made to the sample code occurs in the pom. I upgraded the jackson dependency to the latest version.
So what am I missing? I have the jackson mapper jars on my classpath. I'm using the <mvc:annotation-driven /> directive in my servlet and I'm using the #ResponseBody annotation with each of my controller methods.
Any help would be greatly appreciated!
Dispatcher servlet:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="uk.co.jeeni" />
<mvc:annotation-driven />
</beans>
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>uk.co.jeeni</groupId>
<artifactId>spring-json</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<name>Spring 3 MVC JSON Example</name>
<properties>
<spring.version>3.2.1.RELEASE</spring.version>
</properties>
<dependencies>
<!--
Jackson mapper is used by spring to convert
Java POJOs to JSON strings.
-->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
<!-- START: Spring web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- END: Spring web -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
</plugin>
</plugins>
<finalName>spring-mvc-json</finalName>
</build>
Controller:
package uk.co.jeeni;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#Controller
public class JsonService {
private static Map<String, Person> data = new HashMap<String, Person>();
static{
data.put("ADAM", new Person("Adam", "Davies", 42));
data.put("JANE", new Person("Jane", "Harrison", 35));
}
#RequestMapping(value="{name}", method = RequestMethod.GET)
public #ResponseBody Person getPerson(#PathVariable String name){
Person p = new Person(name, name, 105);//data.get(name.toUpperCase());
return p;
}
#RequestMapping(value="/testJson.html", method=RequestMethod.GET)
public #ResponseBody List<Person> testJson()
{
List<Person> people = new ArrayList<Person>();
for(int i=0;i<10;i++)
{
Person p = new Person("Firstname", "Lastname", i);
people.add(p);
}
return people;
}
#ResponseBody
#RequestMapping(value="testJsonPojo.html", method=RequestMethod.GET)
public Person testJsonPojo()
{
Person individual = new Person("Firstname", "Lastname", 105);
return individual;
}
}
Person.java:
package uk.co.jeeni;
public class Person {
private String firstName;
private String lastName;
private int age;
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
The mapped URL's for the methods that are not working end with .html. That doesn't make sense because you are returning JSON data. I suggest you change the mapping like:
#RequestMapping(value="/testJson.json", method=RequestMethod.GET)
Because of the extension, Spring sets the request's media type to html, so it is not forwarded to a JSON view.
It might be a problem with your mvc:annotations introduced in 3.2 that's been answered here:
https://stackoverflow.com/a/13939290/3014094
There's an additional change to mvc:annotations needed in Spring 3.2. It's trying to automatically assign the media type based on the extension of the request. I'd guess that it's likely to be /doSomething.html which is not mapping to JSON.
Update your mvc spring config to turn this auto-mapping off
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<!-- Turn off working out content type based on URL file extension, should
fall back to looking at the Accept headers -->
<property name="favorPathExtension" value="false" />
</bean>