.Net C# 使用 IKVM 调用 Java 代码

相关开源库

https://github.com/ikvm-revived

版本号

  • .Net 6
  • JDK 8
  • IKVM 8.2.1

IKVM 在 8.2.0 版本中新增加 IkvmReference

(在 MSBuild 中配置. 自动帮你编译jar到dll 和 自动引用dll )

所以本文就用这个了.

不再使用 ikvmc 手动编译, 太繁琐了,

手动输入 ikvm -jar 和 ikvmc 有 java -jar 和 javac 的感觉了.


nuget 第一次安装 ikvm 可能需要点时间,
因为 ikvm 的 dll 比较大. 耐心等待一下.
会保存到 C:\Users\Administrator\.nuget\packages\ikvm\
以后安装同版本的 ikvm 就不用再重复下载了.

说明

首先得有 Java 代码

本文使用

java 的 SM2 加密 (测试自己写的java代码)

和 hutool 中的 简易 FTP 来举例 (测试 第三方依赖 +二级依赖)

SM2 中也使用了 hutool

Java Maven 部分

直接创建一个 Maven 空项目, 开始写代码.

第一部分是 依赖项

第二部分是 打包代码和依赖到一个jar中 (下面有说明为什幺要打包成一个jar)

代码写完后, 在IDEA右侧的 maven 里 双击 package 进行打包.

就会看到输出目录有一个 8.9M 的 netjar.jar

( 如果你只有别人提供的jar包, 也可以 手动执行 jar包的解压和压缩. 把多个jar合成一个 ,

如果只有class文件, 那就得手动创建多层文件夹 和 java 的 package 名称匹配上. 再用命令 压缩为jar)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.xue</groupId>
    <artifactId>netjar</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
<!--    依赖-->
    <dependencies>
<!--        hutool 和 依赖的ftp包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ftpserver</groupId>
            <artifactId>ftpserver-core</artifactId>
            <version>1.2.0</version>
        </dependency>        
<!--       加密相关-->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
<!--        一些工具类-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.36</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
<!--            将所有依赖打包到一个jar中-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <appendAssemblyId>false</appendAssemblyId>
                    <finalName>netjar</finalName>
                    <descriptorRefs>
                        <!-- 将依赖的jar包中的class文件打进生成的jar包-->
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <!--
                             Main函数的类,生成的jar包 使用命令执行时的入口函数,
                             如果不需要一个入口. 那就可以随便写一个 唯一的类就行. 不影响
                            -->
                            <mainClass>com.xue.netjar.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <!-- <goal>single</goal>-->
                            <goal>assembly</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

为什么要打包成1个 jar ?

如果每个依赖都打1个包, 那这里会出现9个jar ,

就得在.csproj 配置中 写9遍 指定jar位置 (可能以后会支持指定文件夹吧),

打包成1个就只需要写1遍了.

其实只指定jar位置还不行, IKVM 在执行代码时 , 就会说 找不到 XXX 依赖.

所以你还需要指定依赖 References ,

例子中的 h1 h2 h3 都是 常规的 第三方依赖 , 比如 hutool,

my-code 是 自己写的代码. (java 写的SM2加密)

<ItemGroup>
   
   <IkvmReference Include="files/h1.jar"/>
   <IkvmReference Include="files/h2.jar"/>
   <IkvmReference Include="files/h3.jar"/>
   
   <IkvmReference Include="my-code.jar">
      <AssemblyName>MyCode</AssemblyName>
      <AssemblyVersion>1.0.0.0</AssemblyVersion>
      <References>files/h1.jar;files/h2.jar;files/h3.jar;</References>      
   </IkvmReference>
   
</ItemGroup>

真实写法, jar包多了, 那就太痛苦了.

<IkvmReference Include="jar/bcprov-jdk15on-1.64.jar" />
<IkvmReference Include="jar/commons-lang3-3.12.0.jar" />
<IkvmReference Include="jar/hutool-all-5.6.3.jar" />
<IkvmReference Include="jar/Sm2Util.jar" >
	<AssemblyName>Sm2Util</AssemblyName>
	<AssemblyVersion>1.0.0.1</AssemblyVersion>
	<References>jar/hutool-all-5.6.3.jar;jar/bcprov-jdk15on-1.64.jar;jar/commons-lang3-3.12.0.jar</References>
</IkvmReference>

这种配置文件形式, 估计底层也是调用旧的命令方式去转为dll ( 可以看到很多老文章都是手动 搞 ikvmc 命令)

所以我们要打包成一个jar, 不用写一堆 Include , 也不用 写一堆 References 了

省了不少事情, 直接 写一个 Include , 啥也不用操心了.

C# 部分

在vs中新建一个名为jar的文件夹, 把 netjar.jar 放进来.

.csproj 中添加 IkvmReference , 再添加 Include 为 jar/netjar.jar

指定 AssemblyName ( 编译后的 就是 netjar.dll ) (其他的第三方包不用指定, 会自动识别)

AssemblyVersion 必须是 1.0.0.0 这种 4部分的版本号, 会给dll加上版本信息. (估计内部会根据版本号缓存dll)

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net6.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="IKVM" Version="8.2.1" />
	</ItemGroup>

	<ItemGroup>
		<IkvmReference Include="jar/netjar.jar" >
			<AssemblyName>netjar</AssemblyName>
			<AssemblyVersion>1.0.0.4</AssemblyVersion>
		</IkvmReference>
	</ItemGroup>

</Project>

保存后, 重新生成下 解决方案.

此时 写代码 应该已经有 智能提示了.

最终测试一下

非常的完美哦. 功能都正常.

namespace IkvmDemo;

using cn.hutool.core.util;
using cn.hutool.extra.ftp;
using cn.hutool.http;
using cn.hutool.http.server;
using cn.hutool.http.server.action;

using com.xue.netjar; // 自己用java写的 SM2 

internal class Program
{
    static void Main(string[] args)
    {
        //*******************
        // 测试一下 Java 的 SM2 加密
        //var res2 = new Sm2Util()
        //    .encrypt(
        //    "我是内容",
        //    "publicKey太长,省略了.",
        //    "GBK");

        //Console.WriteLine(res2);

        //*******************
        // 调用一下 java 的 main 方法
        //com.xue.netjar.Main.main(args);

        //*******************
        // 测试一下 hutool 的 IdCard 帮助类. 获取 归属地
        //var idCard = "142731195005152222";
        //var res = IdcardUtil.getProvinceByIdCard(idCard);
        //Console.WriteLine(res);

        //*******************
        // 启动 Ftp
        //SimpleFtpServer.create().addAnonymous("E:/").start();


        //**************
        // 启动 http服务器
        HttpUtil.createServer(8000).addAction("/", new MyAction()).start();

        //Console.ReadLine();
    }

}
// 有点小遗憾, c#没有 匿名内部类, 只能写一个完整的类, 去实现 hutool 的 Action 接口
public class MyAction : Action
{
    public void doAction(HttpServerRequest req, HttpServerResponse res)
    {       
        res.write("hi");
    }
}

目录结构

在这里插入图片描述

在这里插入图片描述

题外话

2022.08.11

https://github.com/ikvm-revived/ikvm-maven

发现作者新开了一个仓库, 这是要给 IKVM 扩展一个 C# 里的 maven 呀

直接 指定一个包名称和版本号, 就能从 maven 仓库 自动拉取依赖. 不用自己折腾本地jar包了.

和 java 用 maven 一模一样.

不过还处在早期 ( 刚写1个月 ), 只实现了基本的 单包拉取 ,

还不会自动分析依赖.

也不能手动指定 之前那个 References 依赖,

执行代码的时候还是会报 找不到xxx依赖


2022.08.11

看 IKVM 的 issues , 好像作者 最近已经开始 兼容 JDK9. (要兼容到最新JDK的节奏? )

这是要兼容 java 所有生态啊 ,太强了…

如果以后 ikvm-maven 完成, 写个包名 直接开始用.

和 C# 用 nuget 一样, 轻轻松松.

那真是无敌了.


2022.08.11

从某个评论区找到一个替代品, 好像是收费的. 也不开源.

https://github.com/masesgroup/JCOBridge-Examples

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值