Можно ли создать URL, указывающий на объект в памяти?

Я пытаюсь расширить мою библиотеку для интеграции Swing а также JPA делая JPA Конфигурация как автоматическая (и переносимая), как это может быть сделано, и это означает программное добавление <class> элементы. (Я знаю, что это можно сделать через Hibernate's AnnotationConfiguration или EclipseLInk's ServerSession, но - мобильность). Я также хотел бы избежать использования Spring только для этой единственной цели.

Я могу создать persistence.xml на лету, и заполните его <class> элементы из указанных пакетов (через библиотеку Reflections). Проблема начинается, когда я пытаюсь накормить это persistence.xml к JPA поставщик. Единственный способ, которым я могу думать, - это создать URLClassLoader, но я не могу придумать способ, который не заставил бы меня сначала записать файл на диск где-нибудь, для единственной возможности получить действительный URL, Настройка сокета для обслуживания файла через URL (localhost:xxxx Кажется... я не знаю, зло?

У кого-нибудь есть идеи, как можно решить эту проблему? Я знаю, что это большая работа, чтобы избежать использования одной библиотеки, но я просто хотел бы знать, можно ли это сделать.

РЕДАКТИРОВАТЬ (попытка быть более ясным):

Динамически генерируется XML хранится в String объект. Я не знаю, как сделать это доступным для постоянного поставщика. Кроме того, я хочу избежать записи файла на диск.

В целях моей проблемы поставщик постоянства - это просто класс, который сканирует путь к классам для META-INF/persistence.xml, Некоторые реализации могут быть сделаны для принятия динамического создания XML, но нет общего интерфейса (особенно для важной части файла, <class> теги).

Моя идея состоит в том, чтобы настроить ClassLoader - если у вас есть другие, я был бы благодарен, я не настроен на это.

Единственный легко расширяемый / настраиваемый, который я мог найти, был URLClassLoader, Работает на URL объекты, и я не знаю, смогу ли я создать его, не записав сначала XML на диск.

Вот как я настраиваю вещи, но это работает, написав persistenceXmlFile = new File("META-INF/persistence.xml") на диск:

Thread.currentThread().setContextClassLoader(
    new URLResourceClassLoader(
        new URL[] { persistenceXmlFile.toURI().toURL() },
        Thread.currentThread().getContextClassLoader()
    )
);

URLResourceClassLoader является URLCLassLoader подкласс, который позволяет искать ресурсы и классы, переопределяя public Enumeration<URL> findResources(String name),

2 ответа

Может быть, немного поздно (через 4 года), но для тех, кто ищет подобное решение, вы можете использовать созданную мной фабрику URL:

public class InMemoryURLFactory {

    public static void main(String... args) throws Exception {
        URL url = InMemoryURLFactory.getInstance().build("/this/is/a/test.txt", "This is a test!");
        byte[] data = IOUtils.toByteArray(url.openConnection().getInputStream());
        // Prints out: This is a test!
        System.out.println(new String(data));
    }

    private final Map<URL, byte[]> contents = new WeakHashMap<>();
    private final URLStreamHandler handler = new InMemoryStreamHandler();

    private static InMemoryURLFactory instance = null;

    public static synchronized InMemoryURLFactory getInstance() {
        if(instance == null)
            instance = new InMemoryURLFactory();
        return instance;
    }

    private InMemoryURLFactory() {

    }

    public URL build(String path, String data) {
        try {
            return build(path, data.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException ex) {
            throw new RuntimeException(ex);
        }
    }

    public URL build(String path, byte[] data) {
        try {
            URL url = new URL("memory", "", -1, path, handler);
            contents.put(url, data);
            return url;
        } catch (MalformedURLException ex) {
            throw new RuntimeException(ex);
        }
    }

    private class InMemoryStreamHandler extends URLStreamHandler {

        @Override
        protected URLConnection openConnection(URL u) throws IOException {
            if(!u.getProtocol().equals("memory")) {
                throw new IOException("Cannot handle protocol: " + u.getProtocol());
            }
            return new URLConnection(u) {

                private byte[] data = null;

                @Override
                public void connect() throws IOException {
                    initDataIfNeeded();
                    checkDataAvailability();
                    // Protected field from superclass
                    connected = true;
                }

                @Override
                public long getContentLengthLong() {
                    initDataIfNeeded();
                    if(data == null)
                        return 0;
                    return data.length;
                }

                @Override
                public InputStream getInputStream() throws IOException {
                    initDataIfNeeded();
                    checkDataAvailability();
                    return new ByteArrayInputStream(data);
                }

                private void initDataIfNeeded() {
                    if(data == null)
                        data = contents.get(u);
                }

                private void checkDataAvailability() throws IOException {
                    if(data == null)
                        throw new IOException("In-memory data cannot be found for: " + u.getPath());
                }

            };
        }

    }
}

Для этого мы можем использовать библиотеку Google Jimfs .

Во-первых, нам нужно добавить в наш проект зависимость maven :

      <dependency>
  <groupId>com.google.jimfs</groupId>
  <artifactId>jimfs</artifactId>
  <version>1.2</version>
</dependency>

После этого нам нужно настроить поведение нашей файловой системы и записать содержимое String в файл в памяти, например:

      public static final String INPUT =
      "\n"
          + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
          + "<note>\n"
          + "  <to>Tove</to>\n"
          + "  <from>Jani</from>\n"
          + "  <heading>Reminder</heading>\n"
          + "  <body>Don't forget me this weekend!</body>\n"
          + "</note>";

  @Test
  void usingJIMFS() throws IOException {
    var fs = Jimfs.newFileSystem(Configuration.unix());
    var path = fs.getPath(UUID.randomUUID().toString());
    Files.writeString(path, INPUT);
    var url = path.toUri().toURL();

    assertThat(url.getProtocol()).isEqualTo("jimfs");
    assertThat(Resources.asCharSource(url, UTF_8).read()).isEqualTo(INPUT);
  }

Мы можем найти больше примеров в официальном репозитории .

Если мы заглянем в исходный код jimfs, мы обнаружим, что реализация похожа на ответ @NSV.

Другие вопросы по тегам