Add Spring JDBC support based on annotations - java

I have task to upgrade Map based storage to DB based storage. My project configuration is based on annotations. Could you explain to me which steps should I take to make it happen? And how will change my dao layer code:
public class TicketDao {
Set<Ticket> tickets = new HashSet<>();
public Set<Ticket> getAll() {
return tickets;
}
public void remove(Ticket ticket){
tickets.remove(ticket);
}
public void put(Ticket ticket){
tickets.add(ticket);
}
}

Create db and schema
Configure DataSource and JdbcTemplate. The simpliest configuration:
#Configuration
public class JdbcConfig {
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl("");
dataSource.setUsername("");
dataSource.setPassword("");
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
Inject JdbcTemplate into dao and use it
public class TicketDao {
public static final String DELETE_QUERY = "delete from Ticket where id = ?";
public static final String INSERT_QUERY = "insert into Ticket values(?, ?)";
public static final String GET_ALL_QUERY = "select * from Tickets";
#Autowired
JdbcTemplate jdbcTemplate;
public Set<Ticket> getAll() {
return new HashSet<>(jdbcTemplate.query(GET_ALL_QUERY, new RowMapper<Ticket>() {
#Override
public Ticket mapRow(ResultSet rs, int rowNum) throws SQLException {
Ticket ticket = new Ticket();
ticket.setId(rs.getString(1));
//other fields mapping
return ticket;
}
}));
}
public void remove(Ticket ticket){
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement statement = con.prepareStatement(DELETE_QUERY);
statement.setString(1, ticket.getId());
return statement;
}
});
}
public void put(Ticket ticket){
Object[] values = {ticket.getId(), ticket.getName()};
int[] types = {Types.VARCHAR, Types.VARCHAR};
jdbcTemplate.update(INSERT_QUERY, values, types);
}
}

Related

Export from Oracle and Import to Azure SQL reusing Entities Spring Boot

I'm trying to fetch data from an Oracle DB and import it to Azure Sql. The databases have the same structure and therefore I was thinking if I could use the same entities and repositories with different datasources for it.
#Entity
#Table(name = "Street", indexes = {#Index(name = "street_id_index", columnList = "streetid")})
public class Street {
#Id
private String streetid;
public String streetcode;
public String streetname;
public String streetnameaddd;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "municipalitycode", referencedColumnName = "municipalitycode")
public Municipality municipalitycode;
public String is_deleted;
}
public interface Street_Repository extends JpaRepository<Street,String> {
List<Street> findAll();
}
#Configuration
public class AzureConfig {
#Bean("AzureDataSource")
#ConfigurationProperties(prefix = "spring.datasource-azure-sql")
public DataSource dataSourceAzureSql(){
return DataSourceBuilder.create().build();
}
}
#Configuration
public class OracleConfig {
#Bean
#ConfigurationProperties(prefix = "spring.datasource-oracle")
public DataSource dataSourceOracle(){
return DataSourceBuilder.create().build();
}
}
spring:
datasource-azure-sql:
jdbc-url: jdbc:sqlserver://xxxxxxx.database.windows.net:1433;database=xxxxxxxxxxx-xxx;user=xxxxx#xxxxx;password=xxxxxxxxx;encrypt=true;trustServerCertificate=false;hostNameInCertificate=xxxxxxxx;loginTimeout=30
datasource-oracle:
jdbc-url: jdbc:oracle:thin:#xxxxx.xx.xxx:xxx:ssid
#Repository
public class Stree_Repo implements Street_Repository {
private JdbcTemplate jdbcTemplate;
#Autowired
#Qualifier("AzureDataSource")
public void setDataSource(DataSource dataSource){
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Autowired
#Qualifier("OracleDataSource")
public void setDataSource2(DataSource dataSource){
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
public List<Street> findAll() {
return null;
}
... rest override methods...
}
So the classe Street_Repo implements the interface and because this Entity is part of both Oracle and Azure I was wondering if there was a possible of not repeating the Entity and all the other classes associated.
Thank you in advance!

NullPointerException when Testing Service and DAO class JUnit

I am testing a DAO class using JUnit and I am getting a nullpointerexception which I am not sure why as I am initiating the service class. The following is the test class:
public class RegisterTest {
private UserDaoImpl userservice = new UserDaoImpl();
#Mock
JdbcTemplate jdbcTemplate;
User user;
#Before
public void setUp() {
user = new User();
}
#Test
public void testSetAddress() {
user.setAddress("A");
assertEquals(user.getAddress(), "A");
}
#Test
public void testSetEmail() {
user.setEmail("B");
assertEquals(user.getEmail(), "B");
}
#Test
public void testSetFirstname() {
user.setFirstname("C");
assertEquals(user.getFirstname(), "C");
}
#Test
public void testSetLastname() {
user.setLastname("D");
assertEquals(user.getLastname(), "D");
}
#Test
public void testSetPassword() {
user.setPassword("E");
assertEquals(user.getPassword(), "E");
}
#Test
public void testSetUsername() {
user.setUsername("F");
assertEquals(user.getUsername(), "F");
}
#Test
public void testRegister() {
userservice.register(user);
String username = user.getUsername();
assertEquals(userservice.findByUsername(username), 1);
}
}
The following is the UserDaoImpl
public class UserDaoImpl implements UserDao {
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
DataSource datasource;
#Autowired
JdbcTemplate jdbcTemplate;
public List<User> findByUsername(String username) {
String sql = "select * from users where username='" + username +
"'";
List<User> users = jdbcTemplate.query(sql, new UserMapper());
return users;
}
public int register(User user) {
// If username is unique
String uniqueusername = "select * from users where username='" +
user.getUsername() + "'";
List<User> users = jdbcTemplate.query(uniqueusername, new
UserMapper());
if(users.size() == 0) {
// encode password
String encryptedPassword =
passwordEncoder.encode(user.getPassword());
// Updating database with new user
String sql = "insert into users values(?,?,?,?,?,?)";
return jdbcTemplate.update(sql, new Object[] {
user.getUsername(),
encryptedPassword,
user.getFirstname(),
user.getLastname(),
user.getEmail(),
user.getAddress() });
}
else {
return 0;
}
}
How can I inject the class in the test class? I guess the reason why the nullpointerxeception is because the dao class is not being injected properly in the test class
You should run your test with adequate runner
RunWith(MockitoJunitRunner.class)
public class RegisterTest {
Then you need to inject your mock inside the DAO
#InjectMocks
private UserDaoImpl userservice = new UserDaoImpl();

Xml file contains no data after i run my application

console after app runsI'm building an application that reads data from h2 database and write it into xml file. The program runs with no errors, but there is no data been written to my xml file.
I created main class
controller class: (family.java) contains setters.
Test Config class: contains all steps needed to read and write the data.
application Properties: contains the information needed to connect to database.
family Data: file i created to transfer data from h2db.
data Sql file : the sql file i use to create my table.
application.prperties
spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.h2.console.path=/h2-console
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:navin
spring.datasource.data-username=sa
spring.datasource.data-password=
data.sql
DROP TABLE IF EXISTS family;
CREATE TABLE family (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(250) NOT NULL,
description VARCHAR(250) NOT NULL
);
INSERT INTO family (name, description) VALUES
('zakaria', 'I am the father'),
('Yahya', 'I am the oldest son in the house'),
('Zaid', 'I am the middle son in the house'),
('Mouad', 'I am the cutest boy in the house');
#Configuration
#EnableBatchProcessing
public class TestConfig {
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
public DataSource dataSource;
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("dataSorce.driverClassName");
dataSource.setUrl("dataSource.url");
dataSource.setUsername("dataSource.username");
dataSource.setPassword("dataSource.password");
return dataSource;
}
public JdbcCursorItemReader<family> reader(){
JdbcCursorItemReader<family> reader = new JdbcCursorItemReader<family>();
reader.setDataSource(dataSource);
reader.setSql("SELECT id,name,description FROM family");
reader.setRowMapper(new FamilyRowMapper());
return reader;
}
public class FamilyRowMapper implements RowMapper<family> {
#Override
public family mapRow(ResultSet rs, int rowNum) throws SQLException {
family user = new family();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setDescription(rs.getString("description"));
return user;
}
}
#Bean
public StaxEventItemWriter<family> writer(){
StaxEventItemWriter<family> writer = new StaxEventItemWriter<family>();
writer.setResource(new ClassPathResource("familyData.xml"));
Map<String, String> aliasesMap = new HashMap<String, String>();
aliasesMap.put("family", "Test_example.family");
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliasesMap);
writer.setMarshaller(marshaller);
writer.setRootTagName("familyData");
writer.setOverwriteOutput(true);
return writer;
}
#Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<family, family> chunk(10)
.reader(reader())
.writer(writer())
.build();
}
#Bean
public Job exportFamilyJob() {
return jobBuilderFactory.get("exportFamilyJob")
.incrementer(new RunIdIncrementer())
.flow(step1())
.end()
.build();
}
}
//family class
public class family {
int id;
String name;
String description;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String saySomething () {
return "my name is :" + name + " " + description + " " + id;
}
}
You need to use FileSystemResource instead of ClasspathResource in the writer:
writer.setResource(new FileSystemResource("familyData.xml"));

Clarify the sequence of events in a Spring MVC ORM web app project

My professor gave a sample Spring MVC ORM project with Hibernate but I can not figure out the sequence of events involved, in particular about the usage of service business object.
This is just a little part of the project, just to make my ideas clearer.
domain:
#Entity
#Table(name = "department")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long uid;
private String name;
#OneToMany(mappedBy="department",cascade=CascadeType.PERSIST)
private List<Employee> employees = new ArrayList<Employee>();
public Department() {
}
public Department(String name) {
this.name = name;
}
// getters, setters, hashcode() and equals(), toString()...
controller:
#Controller
#RequestMapping("/department")
public class DepartmentController {
#Autowired
#Qualifier("departmentBO")
private DepartmentBO departmentBO;
static final Logger logger = Logger.getLogger(DepartmentController.class);
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String departmentHome(Model model) {
logger.debug("department home() invoked");
List<Department> list = departmentBO.findAllDepartments();
model.addAttribute("list", list);
return "departments";
}
// i'll paste just the first controller ;)
business:
public interface DepartmentBO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department department);
public void update(Department department);
}
business/impl:
#Service
#Transactional
public class DepartmentBoImpl implements DepartmentBO {
#Autowired
private DepartmentDAO departmentDao;
static final Logger logger = Logger.getLogger(DepartmentBoImpl.class);
#Override
public void save(Department department) {
departmentDao.save(department);
}
#Override
public void update(Department department) {
departmentDao.update(department);
}
#Override
public void delete(long uid) {
departmentDao.delete(uid);
}
#Override
public List<Department> findAllDepartments() {
return departmentDao.findAllDepartments();
}
#Override
public Department findByUid(Long uid) throws DataAccessException {
return departmentDao.findByUid(uid);
}
}
dao:
public interface DepartmentDAO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department user);
public void update(Department user);
}
dao/impl:
#Repository
public class DepartmentDAOImplSf implements DepartmentDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void delete(long uid) {
Department department = (Department) sessionFactory.getCurrentSession()
.get(Department.class, uid);
sessionFactory.getCurrentSession().delete(department);
}
#Override
public void save(Department department) {
sessionFactory.getCurrentSession().save(department);
}
#Override
public void update(Department department) {
sessionFactory.getCurrentSession().saveOrUpdate(department);
}
#Override
public List<Department> findAllDepartments() {
List<Department> list = (List<Department>) sessionFactory
.getCurrentSession()
.createQuery("FROM Department").list();
return list;
}
#Override
public Department findByUid(Long uid) {
Department department = (Department) sessionFactory
.getCurrentSession().get(Department.class, uid);
return department;
}
}
I know that the order is: domain model -> controller-> service -> dao ->db, but why use a DepartmentBO? and why DepartmentBoImpl autowired DepartmentDao? Who of them act first? Something that i'm not understanding is messing up my conception of how it works and the sequence of the process..
Thanks for your help ;)
EDIT: "
In few words my question is, what is the sequence of this code? user goes on the /home page that redirect on "departments" page. But what happen before this --> "List list = departmentBO.findAllDepartments();" ?;)
When the departmentBO.findAllDepartments() method is called if you look at the code it invokes the sessionFactory. That is an internal factory class in Hibernate that basically builds a transactional connection to the DB in order to run a query. You are defining the query in the createQuery method and then ultimately executing it with the list() method. These two methods are part of the database session that Hibernate has instantiated.
Departments Page -> departmentBO.findAllDepartments() -> sessionFactory -> createQuery -> list()
Or in pseudo code-ish
Departments Page -> execute findAllDepartments method -> fetch / build a database connection -> define the query -> execute the query -> Return the list!

ResultSet in Transaction

I've got a method which returns me a ResultSet object:
#Repository
public class SomeDAOImpl implements SomeDAO{
#Override
public ResultSet getSomething()
{
...
}
}
And this is how I call that:
#Service
public class SomeServiceImpl implements SomeService{
#Autowired
private SomeDAO someDAO;
#Transactional
#Override
public void doSomething()
{
someDAO.getSomething();
...
}
}
Questions:
Do I have to close ResultSet?
Is it ok to return ResultSet object?
1 Yes you should close a ResultSet.
2 I suggest you to return an Object and not a ResultSet.
Here a draft as should be... Here a tutorial.
#Repository
public class SomeDAOImpl implements SomeDAO{
#Override
public User getSomething(String username){
User user = getJdbcTemplate().queryForObject("SELECT * FROM USER WHERE USERNAME = ?",
new Object[] { username },
new UserMapper()
);
return user;
}
private class UserMapper implements RowMapper<User>{
#Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt("ID"));
user.setUsername(rs.getString("USERNAME"));
user.setName(rs.getString("NAME"));
return user;
}
}
}

Categories

Resources