Возможно ли иметь persistence.xml в другом месте, кроме META-INF?

Я хочу, чтобы мой файл persistence.xml в conf моего приложения. Как я могу сказать Persistence.createEntityManagerFactory, что он должен прочитать его оттуда?

Ответ 1

Методы createEntityManagerFactory ищут файлы persistence.xml в каталоге META-INF любого элемента CLASSPATH. если ваш CLASSPATH содержит каталог conf, вы можете поместить определение EntityManagerFactory в conf/META-INF/persistence.xml

Ответ 2

Если вы используете EclipseLink, вы можете установить местоположение persistence.xml с помощью свойства единицы сохранения, "eclipselink.persistencexml".

properties.put("eclipselink.persistencexml", "/org/acme/acme-persistence.xml");
EntityManagerFactory factory = Persistence.createEntityManagerFactory("acme", properties);

Ответ 3

Это решение сработало для меня

    Thread.currentThread().setContextClassLoader(new ClassLoader() {
        @Override
        public Enumeration<URL> getResources(String name) throws IOException {
            if (name.equals("META-INF/persistence.xml")) {
                return Collections.enumeration(Arrays.asList(new File("conf/persistence.xml")
                        .toURI().toURL()));
            }
            return super.getResources(name);
        }
    });
    Persistence.createEntityManagerFactory("test");

Ответ 4

ClassLoader может быть URLClassLoader, поэтому попробуйте его следующим образом:

        final URL alternativePersistenceXmlUrl = new File("conf/persistence.xml").toURI().toURL();

    ClassLoader output;

    ClassLoader current = Thread.currentThread().getContextClassLoader();

    try{

        URLClassLoader parent = (URLClassLoader)current;

        output = new URLClassLoader(parent.getURLs(), parent){

            @Override
            public Enumeration<URL> getResources(String name) throws IOException {

                if (name.equals("META-INF/persistence.xml")) {

                    return Collections.enumeration(Arrays.asList(alternativePersistenceXmlUrl));
                }

                return super.getResources(name);
            }
        };
    }catch(ClassCastException ignored) {

        output = new ClassLoader() {

            @Override
            public Enumeration<URL> getResources(String name) throws IOException {

                if (name.equals("META-INF/persistence.xml")) {

                    return Collections.enumeration(Arrays.asList(alternativePersistenceXmlUrl));
                }

                return super.getResources(name);
            }
        };
    }

Он должен работать. Работает для меня при определенных условиях тестирования и т.д. Пожалуйста, это взломать и не использовать в производстве.

Ответ 5

Мое решение для EclipseLink 2.7.0 и Java 9, и это измененная и подробная версия ответа @Evgeniy Dorofeev.

В org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor на line 236 мы видим следующий код:

URL puRootUrl = computePURootURL(descUrl, descriptorPath);

Этот код используется EclipseLink для вычисления корневого url пути persistence.xml. Это очень важно, потому что окончательный путь будет сделан путем добавления descriptorPath в puRootUrl.

Итак, предположим, что у нас есть файл на /home/Smith/program/some-folder/persistence.xml, тогда мы имеем:

Thread currentThread = Thread.currentThread();
ClassLoader previousClassLoader = currentThread.getContextClassLoader();
Thread.currentThread().setContextClassLoader(new ClassLoader(previousClassLoader) {
    @Override
    public Enumeration<URL> getResources(String name) throws IOException {
        if (name.equals("some-folder/persistence.xml")) {
            URL url = new File("/home/Smith/program/some-folder/persistence.xml").toURI().toURL();
            return Collections.enumeration(Arrays.asList(url));
        }
        return super.getResources(name);
    }

});
Map<String, String> properties = new HashMap<>();
properties.put("eclipselink.persistencexml", "some-folder/persistence.xml");
try {
    entityManagerFactory = Persistence.createEntityManagerFactory("unit-name", properties);
} catch (Exception ex) {
    logger.error("Error occured creating EMF", ex);
} finally {
    currentThread.setContextClassLoader(previousClassLoader);
}

Подробнее:

  • Обратите внимание, что при создании нового загрузчика классов я передаю предыдущий загрузчик классов, иначе он не работает.
  • Положим свойство eclipselink.persistencexml. Если мы этого не сделаем, то по умолчанию дескрипторPath будет равен META-INF/persistence.xml, и нам нужно будет сохранить наш persistence.xml на /home/Smith/program/META-INF/persistence.xml.