12

我正在尝试扩展我的库以进行集成SwingJPA并使JPA配置尽可能自动化(和可移植),这意味着以编程方式添加<class>元素。(我知道它可以通过 HibernateAnnotationConfiguration或 EclipseLInk来完成ServerSession,但是 - 可移植性)。我也想避免Spring仅用于这个单一目的。

我可以动态创建一个persistence.xml,并用指定包中的元素填充它<class>(通过反射库)。当我尝试将其提供persistence.xmlJPA提供商时,问题就开始了。我能想到的唯一方法是设置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()
    )
);

URLResourceClassLoaderisURLCLassLoader的子类,它允许通过覆盖查找资源和类public Enumeration<URL> findResources(String name)

4

2 回答 2

15

可能有点晚了(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());
                }

            };
        }

    }
}
于 2017-08-01T13:25:38.157 回答
0

为此,我们可以使用Jimfs谷歌库。

首先,我们需要将maven 依赖添加到我们的项目中:

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

之后,我们需要配置我们的文件系统行为,并将我们的字符串内容写入内存文件,如下所示:

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 {
  try (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 答案。

于 2021-06-02T22:50:50.923 回答