运行时类加载以支持不断变化的API

我维护一个IntelliJ插件 ,可以改善编写Spock规范的体验。 这个项目的挑战是在单个代码库中支持多个不兼容的IntelliJ API版本。 回想起来,该解决方案很简单(这是狂野的适配器模式的一个示例),但最初它需要一些思想和示例。 我今天再次在代码中修复对新版本的支持 ,因此决定记录一下我最初是如何解决该问题的。

根本问题是我的编译代码可以在存在多个不同API版本的JVM运行时环境中加载。 我的解决方案是将项目分为四个部分:

  • 一个主项目,它不依赖于任何变化的API调用,因此在所有API版本中都是兼容的。 主项目还具有根据其自身所在的运行时环境加载适当的适配器实现的代码。在这种情况下,我可以利用IntelliJ PicoContainer进行服务查找,但是反射API或依赖项注入也具有需要什么。
  • 一组抽象适配器,为主项目提供使用的API。 该项目也不依赖于API版本之间不同的任何代码。
  • 为每个受支持的API版本实现抽象适配器的类集。 每组适配器包装不断变化的API调用,并针对特定的API版本进行编译。

最简单的处理方法是重构API中的某些内容。 这也是实际上破坏了最后一个版本的原因。 我的主要代码需要com.intellij.lang.Language的Groovy实例。 该实例在IntelliJ 14中移动。

该代码一直持续到14岁,因此在这种情况下,我要添加一个新适配器。 在适配器模块中,我有一个抽象类LanguageLookup.java :

package com.cholick.idea.spock;import com.intellij.lang.Language;
import com.intellij.openapi.components.ServiceManager;public abstract class LanguageLookup {public static LanguageLookup getInstance() {return ServiceManager.getService(LanguageLookup.class);}public abstract Language groovy();
}

我支持的最低IntelliJ API版本是11。在11-13之间查找Groovy语言实例是恒定的,因此第一个具体适配器位于针对IntelliJ 11 API编译的模块中。 LanguageLookup11.java :

package com.cholick.idea.spock;import com.intellij.lang.Language;
import org.jetbrains.plugins.groovy.GroovyFileType;public class LanguageLookup11 extends LanguageLookup {public Language groovy() {return GroovyFileType.GROOVY_LANGUAGE;}
}

最新的API引入了重大变化,因此第二个具体适配器位于针对其API版本14编译的模块中。 LanguageLookup14.java :

package com.cholick.idea.spock;import com.intellij.lang.Language;
import org.jetbrains.plugins.groovy.GroovyLanguage;public class LanguageLookup14 extends LanguageLookup {public Language groovy() {return GroovyLanguage.INSTANCE;}
}

最后,主项目有一个SpockPluginLoader.java类,它根据加载的运行时API注册正确的适配器类(我省略了一些与示例无关的方法):

package com.cholick.idea.spock.adapter;import com.cholick.idea.spock.LanguageLookup;
import com.cholick.idea.spock.LanguageLookup11;
import com.cholick.idea.spock.LanguageLookup14;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.impl.ComponentManagerImpl;
import org.jetbrains.annotations.NotNull;
import org.picocontainer.MutablePicoContainer;public class SpockPluginLoader implements ApplicationComponent {private ComponentManagerImpl componentManager;SpockPluginLoader(@NotNull ComponentManagerImpl componentManager) {this.componentManager = componentManager;}@Overridepublic void initComponent() {MutablePicoContainer picoContainer = componentManager.getPicoContainer();registerLanguageLookup(picoContainer);}private void registerLanguageLookup(MutablePicoContainer picoContainer) {if(isAtLeast14()) {picoContainer.registerComponentInstance(LanguageLookup.class.getName(), new LanguageLookup14());} else {picoContainer.registerComponentInstance(LanguageLookup.class.getName(), new LanguageLookup11());}}private IntelliJVersion getVersion() {int version = ApplicationInfo.getInstance().getBuild().getBaselineVersion();if (version >= 138) {return IntelliJVersion.V14;} else if (version >= 130) {return IntelliJVersion.V13;} else if (version >= 120) {return IntelliJVersion.V12;}return IntelliJVersion.V11;}private boolean isAtLeast14() {return getVersion().compareTo(IntelliJVersion.V14) >= 0;}enum IntelliJVersion {V11, V12, V13, V14}
}

最后,在需要Groovy com.intellij.lang.Language的代码中,我获得了LanguageLookup服务的所有权并调用其groovy方法:

...
Language groovy = LanguageLookup.getInstance().groovy();
if (PsiUtilBase.getLanguageAtOffset(file, offset).isKindOf(groovy)) {
...

该解决方案允许相同的已编译插件JAR跨版本11-14支持IntelliJ的各种API。 我以为Android开发人员通常会实现这样的解决方案,但是作为Web应用程序开发人员,我从来不必编写这种解决方案。

翻译自: https://www.javacodegeeks.com/2014/09/runtime-class-loading-to-support-a-changing-api.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361859.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

急救: Autodesk MapGuide Studio - Preview在MapGuide Open Source环境不能进行中文标注

MapGuide环境: 从官方mapguide.osgeo.org下载的最新版Mapguide Open Source1.1 和 MapGuide Open Source Web Server Extension开发环境: vs2005 .net2问题详述:对于图层Layer1. 选中后实体可以查询中文属性信息。具体设置在Properties displayed in Viewer&#xf…

解决新版本webpack vue-cli生成文件没有dev.server.js问题

新版本webpack生成的dev.server.js 在webpack.dev.conf.js中webpack.dev.conf.jsconst axios require(axios) const express require(express) const app express() const apiRoutes express.Router() app.use(/api, apiRoutes)然后找到devserver 这里可以配置路由devServe…

C++内存管理——指针数组

C/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。但二者有着本质的区别:数组:要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是…

ArcGIS中的WKID(转)

ArcGIS中的WKID link: https://www.cnblogs.com/liweis/p/5951032.html 提到坐标系统,大家多少能明白一些,但在运用时,有些朋友搞得不是非常清楚,以后专门来总结。在实地生产项目中,使用较多的2000中国大地坐标系&…

Nashorn如何在新层面上影响API的发展

在上一篇关于如何将jOOQ与Java 8和Nashorn结合使用的文章之后,我们的一位用户发现了使用jOOQ API的缺陷, 如用户组中所述 。 本质上,缺陷可以总结如下: Java代码 package org.jooq.nashorn.test;public class API {public stati…

flex弹性盒子

注意事项 1.设为Flex布局之后,子元素的float,clear和vertical-align属性都讲失效 2.采用Flex布局的元素,称为Flex容器(Flex container),所有的子元素成为容器成员,称为Flex项目(Fle…

Oracle Golden Gate 系列十三 -- 配置GG进程检查点(checkpoint) 说明

一.Checkpoints 理论说明有关GG的Checkpoints 在系列一, GG的架构中以说明:OracleGolden Gate 系列一 --GG 架构 说明http://blog.csdn.net/tianlesoftware/article/details/6925907这里在单独拿出来说明一下,因为这是一个较为重要的概念。Ch…

开始JBoss BPM流程的3种基本方法

这一集提示和技巧将帮助您了解根据需要启动流程实例的最佳方法。 规划项目可能包括流程项目,但是您是否考虑过可以启动流程的各种方式? 也许您的JBoss BPM Suite在您的体系结构中本地运行,也许您在云中运行,但是无论它在哪里&am…

用asp.net编写冒泡排序法

这里写了一个冒泡排序的函数. int[] a newint[10] { 12,564,95,44,69,499,693,6746,6496,124}; for(inti0;i<a.Length;i) for(intj i1; j <10; j) { int min a[i]; if (a[i] > a[j]) //升序排列 …

使用Gradle构建和应用AST转换

最近&#xff0c;我想在Gradle项目中构建并应用本地ast转换。 虽然我可以找到一些有关如何编写转换的示例&#xff0c;但找不到完整的示例来显示完整的构建过程。 转换必须单独编译&#xff0c;然后放在类路径中&#xff0c;因此其源代码不能简单地放在Groovy源代码树的其余部分…

7月17日每日一答

1 什么是闭包函数&#xff0c;闭包函数满足什么样的条件&#xff1f;请写一个常见的闭包函数。 所谓的函数闭包本质是函数的嵌套和高阶函数。我们来看看要实现函数闭包要满足什么条件&#xff08;缺一不可&#xff09;&#xff1a; 1)必须嵌套函数 2)内嵌函数必须引用一个定义在…

vi 常用命令

一、vi简介 vi编辑器是所有Unix及Linux系统下标准的编辑器&#xff0c;它的强大不逊色于任何最新的文本编辑器&#xff0c;这里只是简单地 介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任何版本&#xff0c;vi编辑器是完全相同的&#xff0c;因此您可以在其 他…

Servlet基础(一)

JavaEE&#xff1a;企业级开发技术<一.基础概念>j2ee:jdk1.1--1.4 ----->> j2ee1.1 1.2 javaee:jdk--5,6,7 --->>javaee 5,6,7javaee与servlet,jsp Servlet:前后台传递数据&#xff0c;基于网络的HTTP请求的处理 实现需要借助web容器 J…

BZOJ1706奶牛接力跑

这个东西思路还是不错的。 解法就是把矩阵幂的加法改成取min&#xff0c;乘法改成加法就好&#xff0c;和floyed是一样的。这样的话&#xff0c;矩阵操作一次就相当于松弛了一次最短路。 建矩阵的过程也比较简单&#xff0c;可以离散化&#xff0c;当然下面有另一种更优秀的打法…

EJB 3.x:生命周期和并发模型(第2部分)

这是两部分系列的第二篇。 第一部分介绍了有状态和无状态EJB的生命周期以及并发行为。 在这篇文章中&#xff0c;我将介绍Singleton EJB 。 Singleton模式可以说是最常用&#xff08;有时被滥用&#xff01;&#xff09;的模式。 单吨又爱它&#xff01; Java EE使我们无需编…

MVC2中Area的路由注册实现

今天碰到了一个不可思议的bug&#xff0c;新增的controller中任何action都无法访问&#xff0c;都是返回404错误。一般这种错误要么是拼写错误&#xff0c;要么是不小心给action加了post属性&#xff0c;但是经过初步的排查&#xff0c;没有发现问题。而原有的controller中任何…

当Java 8 Streams API不够用时

Java 8与往常一样是妥协和向后兼容的版本。 JSR-335专家组可能无法与某些读者就某些功能的范围或可行性达成一致的发行版。 请参阅Brian Goetz关于为什么…的一些具体解释。 …Java 8默认方法中不允许“最终” …Java 8默认方法中不允许“同步” 但是今天&#xff0c;我们将…

Servlet - cookie、session、servletContext概述

1、cookie 在客户端的小纸条&#xff0c;存储在客户端一个servlet/jsp设置的cookies能被同一路径下面或者子路径下面的servlet/jsp读到&#xff0c;但子路径设置的cookies父路径读不到.添加cookie的方法&#xff1a; Cookie cookie new Cookie("aaa", "bbb&quo…

父类作为方法的形参以及父类作为方法返回值

1、父类作为方法的形参 语句&#xff1a;修饰符 父类类型 方法名(){} 2、父类作为方法返回值 语句&#xff1a;修饰符 void/返回值类型 方法名(父类类型 形参名){} 代码例子&#xff1a; 动物类&#xff1a; /*** author Mr.Wang* 宠物类**/ public abstract class Animals {pr…

在Spring Boot中使用@ConfigurationProperties

在最近的博客文章中&#xff0c;我简短地介绍了如何在Spring Boot应用程序中配置邮件 。 要将属性注入配置中&#xff0c;我使用了Spring的Value注释。 但是Spring Boot提供了一种使用属性的替代方法&#xff0c;该方法允许强类型的Bean来管理和验证应用程序的配置。 在本文中&…