Ответы пользователя по тегу Java
  • Где можно почитать о class-loader?

    EugeneP2
    @EugeneP2
    Java Dev
    Комментировать
  • Чем можно заменить TreeMap?

    EugeneP2
    @EugeneP2
    Java Dev
    Несколько значений по одному и тому же ключу?

    А что вам мешает сделать вот так:
    Map<String, List<String>> mapOfList = new TreeMap<>();


    Еще вариант использовать
    guava multimap

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>19.0</version>
    </dependency>
    Ответ написан
    2 комментария
  • Как вывести матрицу в окно??

    EugeneP2
    @EugeneP2
    Java Dev
    Что за окно? Окно веб браузера, или окно swing? Или консоль?

    Если swing, можно использовать JTable: How to Use Tables
    Ответ написан
  • Для чего используется BindingResult в java?

    EugeneP2
    @EugeneP2
    Java Dev
    Из него мы можем узнать были ли ошибки валидации и какие при байденге http запроса на объект в контроллере

    Например, вот такой у нас контроллер
    @Controller
    public class SearchCommentController {
    
    	...................
    
    	@RequestMapping(method = RequestMethod.POST)
    	public String displayCommentAlert(@Validated FormParams params, BindingResult bindingResult, Model model) {
    		if (bindingResult.hasErrors() == false) {
    			List<CommentWithPeopleDetail> foundComments = commentDao.find(params);
    			model.addAttribute("foundComments", foundComments);
    		}
    		return "commentAlert";
    	}
    
    	...................
    }


    bindingResult инжектится спригом в метод контроллер

    вот валидатор
    public class SearchCommentParamValidator implements Validator {
    
    	@Override
    	public boolean supports(Class<?> clazz) {
    		return FormParams.class.isAssignableFrom(clazz);
    	}
    
    	@Override
    	public void validate(Object target, Errors errors) {
    
    		FormParams params = (FormParams) target;
    
    		if (StringUtils.isBlank(params.getRuleId()) && StringUtils.isBlank(params.getRef())) {
    			errors.reject(null, "Необходимо указать или 'ID правила', и/или 'Объект алерта'!");
    		} else if (params.getDateFrom() == null || params.getDateTo() == null) {
    			errors.reject(null, "Необходимо указать период поиска!");
    		}
    	}
    }
    Ответ написан
    Комментировать
  • Как отправить введенные данные пользователя в метод и вернуть результат?

    EugeneP2
    @EugeneP2
    Java Dev
    int factorial = Main.number(number);
                System.out.print(factorial);
    Ответ написан
    Комментировать
  • Как присоединить Базу данных к своему проекту на GitHub?

    EugeneP2
    @EugeneP2
    Java Dev
    Если БД не большая, то можно использовать встраиваемую (imbedded) базу данных, например H2.

    База будет подыматься вместе с вашим приложением.

    Все что нужно, это подключить в зависимости JDBC драйвер
    <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <version>1.4.192</version>
            </dependency>


    И указать URL с нужными параметрами

    Простой пример
    import java.sql.*;
    
    public class H2Main {
    
        static {
            try {
                Class.forName("org.h2.Driver");
            } catch (ClassNotFoundException e) {
                System.err.println("Error load H2 JDBC driver: " + e.getMessage());
            }
        }
    
    
        public static void main(String[] args) {
    
            try (Connection con = DriverManager.getConnection("jdbc:h2:./h2example", "sa", "")) {
    
                createSimpleDBSchema(con);
    
                System.out.printf("Message from H2: %s\n", getMessage(con));
    
    
            } catch (Exception e) {
                System.err.printf("%s: %s\n", e.getClass().getSimpleName(), e.getMessage());
            }
    
    
        }
    
    
        static void createSimpleDBSchema(Connection con) {
            try (Statement stmt = con.createStatement()) {
    
                stmt.executeUpdate("CREATE TABLE HelloH2 (message varchar(255) NULL);");
    
                stmt.executeUpdate("INSERT INTO HelloH2 (message) VALUES ('Hello World!')");
    
            } catch (SQLException e) {
                System.err.printf("%s: %s\n", e.getClass().getSimpleName(), e.getMessage());
            }
        }
    
    
        static String getMessage(Connection con) throws SQLException {
    
            try (Statement stmt = con.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT message FROM HelloH2")) {
    
                if (rs.next())
                    return rs.getString("message");
                else
                    return null;
    
            }
        }
    
    }
    Ответ написан
    1 комментарий
  • Сортирование матрицы (двухмерного массива) Java?

    EugeneP2
    @EugeneP2
    Java Dev
    Если вы планируете сортировать матрицу, то конечно эффективней будет хранить её в виде одномерного массива, чтоб можно было эффективно отсортировать его с помощью быстрой сортировки реализованной методе sort в класса java.util.Arrays.

    А чтоб с массивом можно было работать как с матрицей, можно реализовать класс-адаптер
    import java.util.Arrays;
    
    public class IntMatrix {
    		private final int[] lineMatrix;
    		private final int n;
    		private final int m;
    
    		public IntMatrix(int[] lineMatrix, int n, int m) {
    
    			if (n < 0 || m < 0 || lineMatrix.length != n * m)
    				throw new IllegalArgumentException();
    
    			this.lineMatrix = lineMatrix.clone();
    			this.n = n;
    			this.m = m;
    		}
    
    		public int get(int i, int j) {
    			if (i < n && j < m)
    				return lineMatrix[i * m + j];
    			else
    				throw new ArrayIndexOutOfBoundsException();
    		}
    
    		public void set(int value, int i, int j) {
    			if (i < n && j < m)
    				lineMatrix[i * m + j] = value;
    			else
    				throw new ArrayIndexOutOfBoundsException();
    		}
    
    		public  void sort() {
    			// готовая реализация быстрой сортировки
    			Arrays.sort(lineMatrix);
    		}
    
    		public int getN() {
    			return n;
    		}
    
    		public int getM() {
    			return m;
    		}
    	}


    Пример использования
    public static void main(String[] args) {
    
    
    		int n = 10, m = 15;
    
    		IntMatrix intMatrix = new IntMatrix(new int[n * m], n, m);
    
    		fillMatrixByRandomValues(intMatrix);
    
    		printMatrix(intMatrix);
    
    		intMatrix.sort();
    
    		System.out.println("---------------");
    
    		printMatrix(intMatrix);
    	}
    
    
    	/** заполнение матрицы случайными числами */
    	static void fillMatrixByRandomValues(IntMatrix matrix) {
    		Random random = new Random();
    		for (int i = 0; i < matrix.getN(); i++) {
    			for (int j = 0; j < matrix.getM(); j++) {
    				matrix.set(random.nextInt(1000), i, j);
    			}
    		}
    	}
    
    	/** печать матрицы в консоль */
    	static void printMatrix(IntMatrix matrix) {
    		for (int i = 0; i < matrix.getN(); i++) {
    			for (int j = 0; j < matrix.getM(); j++) {
    				System.out.printf("%s\t", matrix.get(i , j));
    			}
    			System.out.println();
    		}
    	}


    Линейный массив будет занимать меньше места, чем двумерный. Сортировка реализованная в классе java.util.Arrays хорошо и по скорости и по расходу памяти.
    Ответ написан
    3 комментария
  • Как переправить пользователя на страницу 404?

    EugeneP2
    @EugeneP2
    Java Dev
    Ответ написан
    Комментировать
  • Что собой представляет Java EE (Web) приложение?

    EugeneP2
    @EugeneP2
    Java Dev
    да, интернет банкинг, если он написан на джаве.

    В основном это внутрикорпоративные решение связанные с финансами, типа процессинг транзакций, документооборот, обработка заявок... Если хотите какие-то примеры, смотрите в сторону банков.

    Сервлеты, серверы приложений, сервлет контейнеры, JPA, JMS, база данных, очереди, транзакции, Spring, Hibernate - видите эти слова, это Java EE приложение:)

    Та просто, допустим интернет магазин, например будет сервер Tomcat (сервлет контейнер), скорее всего Spring, база данных + какая нибудь реализация JPA, скорее всего Hibernat. Или вместо реляционной БД, будет Mongodb. Вот это вам и будет Java EE
    Ответ написан
  • Как установить связь между jpa и ajax?

    EugeneP2
    @EugeneP2
    Java Dev
    onclick="unblock(<%=contracts.get(i).getNumber();%>)" в дескриптере пропустили знак равно.

    function unblock() { - наверно функция должна принимать number или id?

    function unblock(id) {

    Сообщить об успешности или не успешности операции на сервере можно с помощью кода статуса в ответе от сервера.

    Например операция удаления

    Сервлет
    @WebServlet("/test")
    public class TestServlet extends HttpServlet {
    
        private static final Logger LOG = LoggerFactory.getLogger(TestServlet.class);
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.getRequestDispatcher("/test.jsp").forward(req, resp);
        }
    
        @Override
        protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            try {
                long id = Long.parseLong(req.getParameter("id"));
                testRemove(id);
                resp.setStatus(200);
            } catch (Exception e) {
                LOG.error("Error remove: {}", e.getMessage());
                resp.setStatus(500);
            }
        }
    
        private void testRemove(long id) {
            if (id < 1) {
                throw new RuntimeException("id can't be < 1");
            }
        }
    }


    JSP старница
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    
    <p>
        <input type="button" value="remove data (OK)" onclick="remove(2)"/>
    </p>
    
    
    <p>
        <input type="button" value="remove data (ERROR)" onclick="remove(-1)"/>
    </p>
    
    
    <script>
        function remove(id) {
    
            var request = new XMLHttpRequest();
    
            request.open('DELETE', '/test?id=' + id, false);
            request.send();
    
            if (request.status == 200) {
                alert('Данные упешно удалены')
            } else {
                alert('Ошибка удаления данных!');
            }
        }
    </script>
    
    </body>
    </html>
    Ответ написан
  • Как правильно сложить две строки?

    EugeneP2
    @EugeneP2
    Java Dev
    for (int i = 0; i < b.length(); i++); точка запятая тут не нужна
    Ответ написан
  • Как в jsp привязать удалить определенный элемент из таблицы?

    EugeneP2
    @EugeneP2
    Java Dev
    1. JSP скриплеты - это очень плохой тон и не рекомендуется делать.

    Это нужно делать в сервлете (не в jsp)
    ContractServiceImpl contractService = new ContractServiceImpl();
         List<Contract> contracts = contractService.getAllContractsForUser(user.getUserId());


    потом contracts передавать в jsp через атрибут реквеста

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         ContractServiceImpl contractService = new ContractServiceImpl();
         List<Contract> contracts = contractService.getAllContractsForUser(user.getUserId());
    
       request.setAttribute("contracts",contracts);
       RequestDispatcher requestDispatcher; 
       requestDispatcher = request.getRequestDispatcher("/you_jsp_page.jsp");
      requestDispatcher.forward(request, response);
    }


    и потом уже на стороне JSP с помощью JSTL выводить данные
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <hmtl>
    ...
    <body>
    <table>
    <c:forEach items="${contracts}" var="contr">
    <tr>
       <td>${contr.name}</td>
       <td>${contr.number}</td>
    
      ....
    </tr>
    </c:forEach>
    </table>
    </body>
    </hmtl>


    2. Если пока не хотите заморачиваться с JavaScript-ом и AJAX-ом, то есть более простой вариант с формой.

    а) у сущности Contract должен быть уникальный id, по которому вы могли бы удалить/выбрать/изменить его.

    б) в JSP вашу таблицу в тег и добавьте еще один столбец с чекбоксом, у которого в качестве value будит id Contract-а. Добавить кнопку "Удалить выбранное".

    <form method="post" action="ваш сервлет">
    <input type="submit" value="Удалить выбранное"/>
    <table>
    <c:forEach items="${contracts}" var="contr">
    <tr>
       <td><input type="checkbox" name="id" value="${contr.id}"/></td>
       <td>${contr.name}</td>
       <td>${contr.number}</td>
    
      ....
    </tr>
    </c:forEach>
    </table>
    </form>


    с) Реализовать в вашем сервлете метод обработки пост запросов где получите из реквеста выбранные Id и выполните удаление.

    @Override
    	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    		String[] ids = req.getParameterValues("id");
    
    		if (ids != null && ids.length > 0) {
    			ContractServiceImpl contractService = new ContractServiceImpl();
    			contractService.removeAll(ids);
    		}
    
    		doGet(req, resp); 
    	}


    doGet(req, resp); - метод реализован выше. Произойдет новая выборка контрактов, только уже без удаленных и передастся в JPS. Обновится страница
    Ответ написан
    Комментировать
  • Есть ли в Java/Spring транзакции на изменение объектов?

    EugeneP2
    @EugeneP2
    Java Dev
    1-й вариант: Не использовать изменяемый объект, а каждый раз, когда вы хотите поменять что-то, создавать новый объект, при этом, сам объект должен быть immutable. Доступ к объекту осуществлять через фабрику. Такое решение имхо будит наиболее правильным.

    Пример:

    immutable класс

    public final class User {
    
    	private final String login;
    	private final Date dateCreate;
    	private final String description;
    	private final Set<String> roles;
    
    	public User(String login, Date dateCreate, String description, Set<String> roles) {
    		this.login = login;
    		this.dateCreate = (Date) dateCreate.clone();
    		this.description = description;
    		this.roles = Collections.unmodifiableSet(roles);
    	}
    
    	public String getLogin() {
    		return login;
    	}
    
    	public Date getDateCreate() {
    		return (Date) dateCreate.clone();
    	}
    
    	public String getDescription() {
    		return description;
    	}
    
    	public Set<String> getRoles() {
    		return roles;
    	}
    }


    Фабрика

    public class UserFactory<T> {
    
    	private final AtomicReference<T> atomicReference;
    
    	public UserFactory(T object) {
    		this.atomicReference = new AtomicReference<>(object);
    	}
    
    	public T getObject() {
    		return atomicReference.get();
    	}
    
    	public void setObject(T object) {
    		atomicReference.set(object);
    	}
    }


    public static void main(String[] args) {
    
    		User user = new User("user1", new Date(), "test user", new HashSet<>(Arrays.asList("READ", "ADD")));
    
    		UserFactory<User> userFactory = new UserFactory<>(user);
    
    		exampleUsingUser(userFactory);
    
    	}
    
    	public static void exampleUsingUser(UserFactory<User> userFactory) {
    
    		User user = userFactory.getObject();
    
    		System.out.println(user.getLogin());
    		System.out.println(user.getDescription());
    		System.out.println(user.getRoles());
    	}


    2-й вариант: эдакий велосипед:) Контролировать доступ через прокси с использованием ReentrantReadWriteLock

    Пример:

    Для начала нам нужно выделить интерфейс класса, состояние объекта которого будет меняться

    public interface Settings {
    
    	String getColor();
    	void setColor(String color);
    
    	String getDescription();
    	void setDescription(String description);
    
    	int getSize();
    	void setSize(int size);
    }


    Реализуем интерфейс

    public class SettingsImpl implements Settings {
    
    	private volatile String color;
    	private volatile String description;
    	private volatile int size;
    
    
    	public static Settings newSettings() {
    		return ProxySettingsKeeper.createProxy(new SettingsImpl());
    	}
    	
    	private SettingsImpl() {
    	}
    
    	@Override
    	public String getColor() {
    		return color;
    	}
    
    	@Override
    	public void setColor(String color) {
    		this.color = color;
    	}
    
    	@Override
    	public String getDescription() {
    		return description;
    	}
    
    	@Override
    	public void setDescription(String description) {
    		this.description = description;
    	}
    
    	@Override
    	public int getSize() {
    		return size;
    	}
    
    	@Override
    	public void setSize(int size) {
    		this.size = size;
    	}
    }


    Прокси

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class ProxySettingsKeeper implements InvocationHandler {
    
    	private final Settings settings;
    
    	private final ReentrantReadWriteLock.ReadLock readLock;
    	private final ReentrantReadWriteLock.WriteLock writeLock;
    
    	public ProxySettingsKeeper(Settings settings) {
    
    		ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    		this.readLock = readWriteLock.readLock();
    		this.writeLock = readWriteLock.writeLock();
    
    		this.settings = settings;
    	}
    
    	public static Settings createProxy(Settings settings) {
    		return (Settings) Proxy.newProxyInstance(settings.getClass().getClassLoader()
    				, new Class[]{Settings.class}
    				, new ProxySettingsKeeper(settings));
    	}
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    		String name = method.getName();
    
    		if (name.startsWith("get")) {
    
    			readLock.lock();
    			try {
    				return method.invoke(settings, args);
    			} finally {
    				readLock.unlock();
    			}
    
    		} else if (name.startsWith("set")) {
    
    			writeLock.lock();
    			try {
    				return method.invoke(settings, args);
    			} finally {
    				writeLock.unlock();
    			}
    		}
    
    		return method.invoke(settings, args);
    	}
    }


    public static void main(String[] args) {
    
    		Settings settings = SettingsImpl.newSettings();
    
    		settings.setDescription("test");
    
    		System.out.println(settings.getDescription());
    	}
    Ответ написан
  • Есть ли в Spring своя библиотека для делания HTTP запросов?

    EugeneP2
    @EugeneP2
    Java Dev
    RestTemplate

    находится в пакете spring-web
    Ответ написан
    Комментировать
  • К какой спецификации относится выражение %{...} в JSP?

    EugeneP2
    @EugeneP2
    Java Dev
    Вообще то не %{...}, а ${...}.

    По моему они появились в версии JSP 2.0
    Ответ написан
  • Как вывести содержимое объекта в JavaServlets?

    EugeneP2
    @EugeneP2
    Java Dev
    вообщем, правильно делать вот так

    и что тут вообще происходит? Вы все еще пишете на джаве 1.4?) И что за кошмарная реализация дао?

    TariffDAO tariffDAO = new TariffDAO();
    
    ...............
    
     tariffDAO.getTariffList(out);
    
    ............
    
    List tariffList = MainDAO.getEntitiesList(new Tariff(), query);
            Tariff tariff = new Tariff();
            for (Object object : tariffList) {
                tariff = (Tariff) object;
                out.write(tariff.toString());
            }


    Должно выглядеть как-то так

    TariffDAO tariffDAO = new TariffDAO();
    
    List<Tariff> tariffList = tariffDAO.getTariffList();
    
    for (Tariff t : tariffList) {
       out.write(t);
    }


    А еще лучше, передавать в качестве атрибута в реквест, как по ссылке выше, и уже в jsp выполнять отображение.

    servlet

    req.setAttribute("tariffList", tariffList);

    JSP

    <c:forEach items="${tariffList}" var="tariff"> 
        <p>${tariff.name}</p>
        <p>${tariff.value}</p>
        ...
    </c:forEach>
    Ответ написан
    Комментировать
  • JSP/JSTL vs Thymeleaf что выбрать?

    EugeneP2
    @EugeneP2
    Java Dev
    Хорошая презентация мир без Jsp. thymeleaf 2.0
    Ответ написан
    Комментировать
  • Как создать шаблон log4j с выводом значения метода?

    EugeneP2
    @EugeneP2
    Java Dev
    Грубоватое решение, но тем не менее...

    Для начало нужно создать реализацию ServletRequestListener, в котором мы будем получать id сессии и ассоциировать с потоком обрабатывающем текущий запрос с помощью ThreadLocal.

    package ua.home.web.listener;
    
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.http.HttpServletRequest;
    
    
    public class RequestListener implements ServletRequestListener {
    
    	private static final ThreadLocal<String> sessionIds = new ThreadLocal<>();
    
    	public static String getCurrentSessionId() {
    		return 	sessionIds.get();
    	}
    
    	@Override
    	public void requestInitialized(ServletRequestEvent servletRequestEvent) {
    		HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
    
    		String id = request.getSession().getId();
    
    		sessionIds.set(id);
    	}
    
    	@Override
    	public void requestDestroyed(ServletRequestEvent servletRequestEvent) {	}
    }


    Листенер можно зарегистрировать или пометив его аннотацией @WebListener (для Servlet API 3.x), или по старинки, прописав его в web.xml

    <listener>
            <listener-class>ua.home.web.listener.RequestListener</listener-class>
        </listener>


    С помощью нашего статического метода ServletRequestListener.getCurrentSessionId() мы сможем получать id сессии вне сервлета.

    Далее нам нужно переопределить метод format класса PatternLayout и прописать новую реализацию в log4j.properties.
    В новой реализации метода, мы будет получать id сессии и заменять наш псевдопаттер в строке лога на id.

    package ua.home.web.log;
    
    import org.apache.log4j.PatternLayout;
    import org.apache.log4j.spi.LoggingEvent;
    import ua.home.web.listener.RequestListener;
    
    public class CustomPatternLayout extends PatternLayout {
    	@Override
    	public String format(LoggingEvent event) {
    		return  super.format(event).replace("%sid", RequestListener.getCurrentSessionId());
    	}
    }


    Файл log4j.properties

    log4j.rootCategory=INFO,S
    log4j.appender.S=org.apache.log4j.ConsoleAppender
    log4j.appender.S.layout=ua.home.web.log.CustomPatternLayout
    log4j.appender.S.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %sid %m%n


    Теперь, если мы где то вызовем, например LOG.info("log message"), то в лог у нас запишется строка:

    2016-08-23 12:20:18 TestServlet [INFO] 441135221F8A492364C836560BDEE15E log message
    Ответ написан
    Комментировать
  • Как сделать, чтобы JDBC использовал мой класс для decimal полей?

    EugeneP2
    @EugeneP2
    Java Dev
    Как-то подменить возвращаемый BigDecimal методом ResultSet#getBigDecimal у вас не выйдет, так как это определено jdbc спецификацией.
    Помимо этого, BigDecimal immutable клаcc, и переопределить его не выйдет, даже если ваш класс Curr расширяет Number, вы сможете только привести их общему типу, т.е. к Number. Попытка привести BigDecimal к Curr или на оборот приведет к ClassCastException.

    Проще сделать как написал Виталий Витренко, но можно заморочиться и запроксить Driver, Connection, Statement и ResultSet и после вызова метода gеBigDecimal выполнять нужные преобразования...

    Вот такой вот велосипед :)

    Прокси псевдо драйвер, который сам регистрируется в DriverManager
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.math.BigDecimal;
    import java.sql.*;
    
    public final class PostgresDriverProxyRegister implements InvocationHandler {
    
    	static {
    		try {
    			DriverManager.registerDriver((Driver) newProxy(new org.postgresql.Driver()));
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    	}
    
    
    	public static Object newProxy(Object target) {
    		Class<?> clazz = defineInterface(target);
    		return clazz == null ? target
    				: Proxy.newProxyInstance(Driver.class.getClassLoader(), new Class[]{clazz}, new PostgresDriverProxyRegister(target));
    	}
    
    	public static Class<?> defineInterface(Object o) {
    
    		if (o == null)
    			return null;
    
    		if (o instanceof Driver)
    			return Driver.class;
    		if (o instanceof Connection)
    			return Connection.class;
    		if (o instanceof Statement)
    			return Statement.class;
    		if (o instanceof PreparedStatement)
    			return PreparedStatement.class;
    		if (o instanceof ResultSet)
    			return ResultSet.class;
    
    		return null;
    	}
    
    
    	private final Object target;
    
    	private PostgresDriverProxyRegister(Object target) {
    		this.target = target;
    	}
    
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    		String methodName = method.getName();
    
    		// в этом блоки можно делать нужные изменения для возвращаемых значений методамы ResultSet
    		if (proxy instanceof ResultSet) {
    			Object invokeResult = method.invoke(target, args);
    			if (invokeResult != null) {
    				if ("getBigDecimal".equals(methodName)) {
    					// округляем до 2-х знаков после запятой
    					BigDecimal bigDecimal = (BigDecimal) invokeResult;
    					invokeResult = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
    				} else if ("getString".equals(methodName)) {
    					// убираем пробелы в начале и конце строки, делаем строку в верхнем регистре
    					String s = (String) invokeResult;
    					invokeResult = s.trim().toUpperCase();
    				}
    			}
    
    			return invokeResult;
    		}
    
    		if (proxy instanceof Driver) {
    			if ("acceptsURL".equals(methodName) || "connect".equals(methodName)) {
    				// меняем префикс на оригинал
    				String url = (String) args[0];
    				if (url.startsWith("jdbc:postgresql-proxy:")) {
    					args[0] = url.replace("jdbc:postgresql-proxy:", "jdbc:postgresql:");
    				}
    			}
    		}
    
    		return invokeAndProxy(method, args);
    	}
    
    	public Object invokeAndProxy(Method method, Object[] args) throws Throwable {
    		Object returnValue = method.invoke(target, args);
    		return newProxy(returnValue);
    	}
    }


    Для самой программы, работы с jdbc никак не изменится, только нужно изменить префикс url-а к БД

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
    
            Class.forName("ua.home.jdbc.driver.warp.postgres.PostgresDriverProxyRegister");
    
            try(Connection connection = DriverManager
                    // используем отличный от оригинала прификс к url 'jdbc:postgresql-proxy:', что бы именно наш драйвер грузился
                    .getConnection("jdbc:postgresql-proxy://localhost:5432/test_db", "test_user", "test_password");
                Statement statement = connection.createStatement();
                ResultSet rs = statement.executeQuery("SELECT 12.65456161 as testDecimal, '  tEsTsTrinG    ' as testString")) {
    
                if (rs.next()) {
                    System.out.printf("testDecimal = '%s'\n", rs.getBigDecimal("testDecimal"));
                    System.out.printf("testString = '%s'\n", rs.getString("testString"));
                }
    
                /* output in console
                        testDecimal = '12.65'
                        testString = 'TESTSTRING'
                */
    
            }
        }
    }
    Ответ написан
    1 комментарий