mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-20 03:26:11 +00:00
feature: Metadata Mapping pattern (#1932)
* metadata-mapping * Update README.md * add class diagram * update README.md * fix identation * Update pom.xml * fix indentation * fix ci * remove e.printstack * fix ci * update class diagram * fix ci * fix ci * fix sc * fix smells * Update DatabaseUtil.java * fix coverage * Update DatabaseUtil.java * Update DatabaseUtil.java * Update DatabaseUtil.java * Update metadata-mapping/README.md Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com> * fix review * fix review * Update App.java * Update App.java * fix review Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package com.iluwatar.metamapping;
|
||||
|
||||
import com.iluwatar.metamapping.model.User;
|
||||
import com.iluwatar.metamapping.service.UserService;
|
||||
import com.iluwatar.metamapping.utils.DatabaseUtil;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* Metadata Mapping specifies the mapping
|
||||
* between classes and tables so that
|
||||
* we could treat a table of any database like a Java class.
|
||||
*
|
||||
* <p>With hibernate, we achieve list/create/update/delete/get operations:
|
||||
* 1)Create the H2 Database in {@link DatabaseUtil}.
|
||||
* 2)Hibernate resolve hibernate.cfg.xml and generate service like save/list/get/delete.
|
||||
* For learning metadata mapping pattern, we go deeper into Hibernate here:
|
||||
* a)read properties from hibernate.cfg.xml and mapping from *.hbm.xml
|
||||
* b)create session factory to generate session interacting with database
|
||||
* c)generate session with factory pattern
|
||||
* d)create query object or use basic api with session,
|
||||
* hibernate will convert all query to database query according to metadata
|
||||
* 3)We encapsulate hibernate service in {@link UserService} for our use.
|
||||
* @see org.hibernate.cfg.Configuration#configure(String)
|
||||
* @see org.hibernate.cfg.Configuration#buildSessionFactory(ServiceRegistry)
|
||||
* @see org.hibernate.internal.SessionFactoryImpl#openSession()
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args.
|
||||
* @throws Exception if any error occurs.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// get service
|
||||
var userService = new UserService();
|
||||
// use create service to add users
|
||||
for (var user: generateSampleUsers()) {
|
||||
var id = userService.createUser(user);
|
||||
LOGGER.info("Add user" + user + "at" + id + ".");
|
||||
}
|
||||
// use list service to get users
|
||||
var users = userService.listUser();
|
||||
LOGGER.info(String.valueOf(users));
|
||||
// use get service to get a user
|
||||
var user = userService.getUser(1);
|
||||
LOGGER.info(String.valueOf(user));
|
||||
// change password of user 1
|
||||
user.setPassword("new123");
|
||||
// use update service to update user 1
|
||||
userService.updateUser(1, user);
|
||||
// use delete service to delete user 2
|
||||
userService.deleteUser(2);
|
||||
// close service
|
||||
userService.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate users.
|
||||
*
|
||||
* @return list of users.
|
||||
*/
|
||||
public static List<User> generateSampleUsers() {
|
||||
final var user1 = new User("ZhangSan", "zhs123");
|
||||
final var user2 = new User("LiSi", "ls123");
|
||||
final var user3 = new User("WangWu", "ww123");
|
||||
return List.of(user1, user2, user3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.iluwatar.metamapping.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* User Entity.
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@ToString
|
||||
public class User {
|
||||
private Integer id;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public User() {}
|
||||
|
||||
/**
|
||||
* Get a user.
|
||||
* @param username user name
|
||||
* @param password user password
|
||||
*/
|
||||
public User(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.iluwatar.metamapping.service;
|
||||
|
||||
import com.iluwatar.metamapping.model.User;
|
||||
import com.iluwatar.metamapping.utils.HibernateUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
/**
|
||||
* Service layer for user.
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserService {
|
||||
private static final SessionFactory factory = HibernateUtil.getSessionFactory();
|
||||
|
||||
/**
|
||||
* List all users.
|
||||
* @return list of users
|
||||
*/
|
||||
public List<User> listUser() {
|
||||
LOGGER.info("list all users.");
|
||||
List<User> users = new ArrayList<>();
|
||||
try (var session = factory.openSession()) {
|
||||
var tx = session.beginTransaction();
|
||||
List<User> userIter = session.createQuery("FROM User").list();
|
||||
for (var iterator = userIter.iterator(); iterator.hasNext();) {
|
||||
users.add(iterator.next());
|
||||
}
|
||||
tx.commit();
|
||||
} catch (HibernateException e) {
|
||||
LOGGER.debug("fail to get users", e);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user.
|
||||
* @param user user entity
|
||||
* @return user id
|
||||
*/
|
||||
public int createUser(User user) {
|
||||
LOGGER.info("create user: " + user.getUsername());
|
||||
var id = -1;
|
||||
try (var session = factory.openSession()) {
|
||||
var tx = session.beginTransaction();
|
||||
id = (Integer) session.save(user);
|
||||
tx.commit();
|
||||
} catch (HibernateException e) {
|
||||
LOGGER.debug("fail to create user", e);
|
||||
}
|
||||
LOGGER.info("create user " + user.getUsername() + " at " + id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user.
|
||||
* @param id user id
|
||||
* @param user new user entity
|
||||
*/
|
||||
public void updateUser(Integer id, User user) {
|
||||
LOGGER.info("update user at " + id);
|
||||
try (var session = factory.openSession()) {
|
||||
var tx = session.beginTransaction();
|
||||
user.setId(id);
|
||||
session.update(user);
|
||||
tx.commit();
|
||||
} catch (HibernateException e) {
|
||||
LOGGER.debug("fail to update user", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user.
|
||||
* @param id user id
|
||||
*/
|
||||
public void deleteUser(Integer id) {
|
||||
LOGGER.info("delete user at: " + id);
|
||||
try (var session = factory.openSession()) {
|
||||
var tx = session.beginTransaction();
|
||||
var user = session.get(User.class, id);
|
||||
session.delete(user);
|
||||
tx.commit();
|
||||
} catch (HibernateException e) {
|
||||
LOGGER.debug("fail to delete user", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user.
|
||||
* @param id user id
|
||||
* @return deleted user
|
||||
*/
|
||||
public User getUser(Integer id) {
|
||||
LOGGER.info("get user at: " + id);
|
||||
User user = null;
|
||||
try (var session = factory.openSession()) {
|
||||
var tx = session.beginTransaction();
|
||||
user = session.get(User.class, id);
|
||||
tx.commit();
|
||||
} catch (HibernateException e) {
|
||||
LOGGER.debug("fail to get user", e);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close hibernate.
|
||||
*/
|
||||
public void close() {
|
||||
HibernateUtil.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.iluwatar.metamapping.utils;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
|
||||
/**
|
||||
* Create h2 database.
|
||||
*/
|
||||
@Slf4j
|
||||
public class DatabaseUtil {
|
||||
private static final String DB_URL = "jdbc:h2:mem:metamapping";
|
||||
private static final String CREATE_SCHEMA_SQL = "DROP TABLE IF EXISTS `user`;"
|
||||
+ "CREATE TABLE `user` (\n"
|
||||
+ " `id` int(11) NOT NULL AUTO_INCREMENT,\n"
|
||||
+ " `username` varchar(255) NOT NULL,\n"
|
||||
+ " `password` varchar(255) NOT NULL,\n"
|
||||
+ " PRIMARY KEY (`id`)\n"
|
||||
+ ");";
|
||||
|
||||
/**
|
||||
* Hide constructor.
|
||||
*/
|
||||
private DatabaseUtil() {}
|
||||
|
||||
/**
|
||||
* Create database.
|
||||
*/
|
||||
static {
|
||||
LOGGER.info("create h2 database");
|
||||
var source = new JdbcDataSource();
|
||||
source.setURL(DB_URL);
|
||||
try (var statement = source.getConnection().createStatement()) {
|
||||
statement.execute(CREATE_SCHEMA_SQL);
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("unable to create h2 data source", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.iluwatar.metamapping.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
/**
|
||||
* Manage hibernate.
|
||||
*/
|
||||
@Slf4j
|
||||
public class HibernateUtil {
|
||||
|
||||
private static final SessionFactory sessionFactory = buildSessionFactory();
|
||||
|
||||
/**
|
||||
* Hide constructor.
|
||||
*/
|
||||
private HibernateUtil() {}
|
||||
|
||||
/**
|
||||
* Build session factory.
|
||||
* @return session factory
|
||||
*/
|
||||
private static SessionFactory buildSessionFactory() {
|
||||
// Create the SessionFactory from hibernate.cfg.xml
|
||||
return new Configuration().configure().buildSessionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session factory.
|
||||
* @return session factory
|
||||
*/
|
||||
public static SessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session factory.
|
||||
*/
|
||||
public static void shutdown() {
|
||||
// Close caches and connection pools
|
||||
getSessionFactory().close();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user