【问题标题】:How to add all classes in a jar to Jersey JAXBContext context如何将 jar 中的所有类添加到 Jersey JAXBContext 上下文
【发布时间】:2015-02-24 20:51:03
【问题描述】:

我有一个装有模型 DTO 的罐子。 我希望这些类(标有@XmlRootElement)可供 Jersey 1 HTTP 客户端使用。我的初始化代码是:

ClientConfig cc = new DefaultClientConfig(MyContextResolver.class);
Client client = Client.create(cc);

在MyContextResolver(实现ContextResolver<JAXBContext>)中,我试过了:

jaxbContext = JAXBContext.newInstance(Class1.class, Class2.class);

它可以工作,但它不是动态的(我必须手动添加类,一个一个)。

I also used Spring and it worked,但我想要一个无 Spring 的解决方案。

有没有更好的解决方案?一种自动扫描 jar 中的所有类并将它们添加到上下文中的方法?谢谢。

【问题讨论】:

    标签: java jaxb jersey jax-rs jersey-1.0


    【解决方案1】:

    您是否有理由希望拥有一个同时处理所有类的上下文?如果名称冲突,您将面临例外的风险。

    为什么不简单地拥有一个 ContextResolver,其工作方式如下:

    Map<Class,JAXBContect> cache = new ConcurrentHashMap<>();
    getContext(Class<?> type) {
     JAXBContect  context = cache.get(type);
     if (context ==  null) }
        context = JAXBContext.newInstance(type);
        cache.put(type,context);
     }
     return context;    
    }
    

    JAXB 将解决必要的类依赖关系(唯一的问题是子类,但那些应该在父类中标记为@XMLSeeAlso)。

    唯一的潜在问题是您会在运行时而不是在启动期间发现任何 JAXB 问题。但与此同时,任何错误都只会影响依赖于错误注释类的客户端,其余的都会起作用。

    【讨论】:

    • 这是一个很好的解决方案,但问题是我的响应类总是相同的。我们称之为响应。此类可以具有相同类型的项目列表,但该类型是动态的。为什么?因为我的休息服务是一个类似 CRUD 的通用列表方法。为了避免冲突,我使用了 xml 命名空间。
    • 通过使用 XmlSeeAlso 我需要明确列出所有可能的类型,即使我添加了一个新类型。这也太元了吗?因为我有很多可能的课程要列出。
    • 我明白了,您可以使用每个包中的 ObjectFactories 在上下文中注册您的类,但它仍然不是“动态的”,只是为您节省了手动将类添加到长列表中以防万一新的包成员。你可以看看 jar 扫描stackoverflow.com/questions/2903082/…。至于 XmlSeeAl,它是用于子/父/通用关系而不是批量加载。
    • 我不经常添加软件包,这样解决方案可能会很有趣。你有任何使用对象工厂的例子吗? (关于 XmlSeeAlso,如果我的类可以是 Response 的子类。)
    • 您使用 ObjectFactory 而不是 JAXBContext.newInstance() 中的类。至于它们的构造/注释方式,使用 jaxb 从模式生成类,您将获得一个(比阅读文档更快、更容易)。您仍然需要手动更新它们。最后,您知道响应的实际类型是什么,因为您为特定类型调用 CRUD 方法。也许您可以使用此信息正确初始化上下文。
    【解决方案2】:

    我最终手动扫描了 jar...

    public static List<Class> listClassesInPackage(String jarName, String packageName) throws IOException {
        packageName = packageName.replaceAll("\\.", "/");
        JarInputStream jarFile = new JarInputStream(new FileInputStream(jarName));
        JarEntry jarEntry = null;
        List<Class> classes = new ArrayList();
        do {
            try {
                jarEntry = jarFile.getNextJarEntry();
                if (jarEntry != null && jarEntry.getName().startsWith(packageName) && jarEntry.getName().endsWith(".class")) {
                    Class<?> forName = Class.forName(jarEntry.getName().replaceAll("/", "\\.").replaceAll(".class", ""));
                    XmlRootElement xmlAnnotation = forName.getAnnotation(XmlRootElement.class);
                    if (xmlAnnotation != null) {
                        classes.add(forName);
                    }
                }
            } catch (ClassNotFoundException | IOException ex) {
                // ignore this class
            }
        } while (jarEntry != null);
        return classes;
    }
    

    调用:

    List<Class> packageClasses = listClassesInPackage(
                    Meta.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "pt.iol.model2");
    jaxbContext = JAXBContext.newInstance(packageClasses.toArray(new Class[0]));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多