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

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


person Evgeniy Dorofeev    schedule 05.12.2012    source источник
comment
Если вы используете Spring, вы можете добиться этого, по крайней мере, используя org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean и указав свойство persistenceXmlLocation для указания на файл.   -  person RJo    schedule 05.12.2012
comment
какая реализация JPA? DataNucleus JPA позволяет указать, где он хранится. Может и другие тоже. Очевидно, что это не часть спецификации JPA.   -  person DataNucleus    schedule 05.12.2012


Ответы (6)


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

person Yogesh A Sakurikar    schedule 05.12.2012
comment
Кажется, я нашел рабочее решение, взгляните на мой ответ - person Evgeniy Dorofeev; 21.12.2012

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

properties.put("eclipselink.persistencexml", "/org/acme/acme-persistence.xml");
EntityManagerFactory factory = Persistence.createEntityManagerFactory("acme", properties);
person James    schedule 05.12.2012
comment
Можно ли использовать это решение, когда файл persistence.xml находится за пределами jar, например, когда путь файла persistence.xml равен /home/foo/downloads/persistence.xml? - person Pavel_K; 09.10.2017
comment
Я пробовал разные варианты и не мог заставить его работать. Отсюда eclipse.org/eclipselink/documentation/2.4/jpa/ расширения/ Currently, this property is used only for the canonical model generator. In the future, it may be used for customizing weaving and application bootstrapping. - person Pavel_K; 10.10.2017

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

    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");
person Evgeniy Dorofeev    schedule 21.12.2012
comment
Можете ли вы немного подробнее рассказать о своем ответе? Я недостаточно знаю о внутренних компонентах пружины, чтобы интерполировать, где мне нужно добавить приведенный выше фрагмент. - person niken; 05.07.2013
comment
Весной я бы рассмотрел static.springsource.org/spring/docs/3.2.x/ в первую очередь - person Evgeniy Dorofeev; 06.07.2013
comment
Я бы использовал ваше решение, но оно не работает с моей конфигурацией: Java 1.6.0_24, EclipseLink 2.3.2. У меня есть исключение javax.persistence.PersistenceException: нет поставщика постоянства для EntityManager с именем XXX. У вас есть идея, почему? - person njames; 12.08.2013
comment
Большое спасибо за хорошую идею. Основываясь на вашем ответе, я нашел и опубликовал ответ для EclipseLink 2.7.0. - person Pavel_K; 10.10.2017

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);
            }
        };
    }

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

person poshjosh    schedule 27.08.2016

Мое решение предназначено для 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);
}

Подробности:

  1. Обратите внимание, что при создании нового загрузчика классов я передаю туда предыдущий загрузчик классов, иначе он не работает.
  2. Устанавливаем свойство eclipselink.persistencexml. Если мы этого не сделаем, то descriptorPath по умолчанию будет равен META-INF/persistence.xml, и нам нужно будет сохранить наш файл persistence.xml на /home/Smith/program/META-INF/persistence.xml, чтобы его можно было найти.
person Pavel_K    schedule 10.10.2017