白小兔的小小站

既然选择了远方,便只顾风雨兼程

0%

Java与kotlin混合编程时的maven配置

kotlin官方文档: https://kotlinlang.org/docs/maven.html

A. 项目结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Demo
├── demo-client
│ ├── src
│   ├── pom.xml
├── demo-application
│   ├── pom.xml
│ ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   └── kotlin
├── demo-domain
│   ├── pom.xml
│ ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   └── kotlin
├── demo-external
│ ├── src
│   ├── pom.xml
├── demo-infrastructure
│   ├── pom.xml
│   ├── src
├── demo-start
│ ├── src
│   ├── pom.xml
├── pom.xml

这是一个包含多个子模块的maven项目。我这里目前只在demo-applicationdemo-domain中同时使用了kotlinjava,不过已经足够证明混合编程的可能性。

B. 目前项目使用的java版本为1.8kotlin版本为1.6.10,其中项目最外层pom.xml的部分配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251


<name>Demo</name>
<groupId>com.leuncle.demo</groupId>
<artifactId>Demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
<spring-boot.version>2.1.3.RELEASE</spring-boot.version>
<kotlin.version>1.6.10</kotlin.version>
<kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.apiVersion>1.6</kotlin.compiler.apiVersion>
</properties>

<modules>
<module>demo-start</module>
<module>demo-client</module>
<module>demo-external</module>
<module>demo-application</module>
<module>demo-domain</module>
<module>demo-infrastructure</module>
</modules>

<dependencyManagement>
<dependencies>
<!-- Log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-bom</artifactId>
<version>2.16.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Project modules -->
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-external</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-application</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-domain</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-infrastructure</artifactId>
<version>${project.version}</version>
</dependency>
<!--SpringBoot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- kotlin -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk7</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-common</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>lombok</plugin>
<plugin>spring</plugin>
<plugin>all-open</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-lombok</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
<sourceDir>src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${plugin.source.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>

上面的内容中值得注意的主要是build部分,pluginManagement主要用于定义各种插件的配置信息,并不会实际引入,需要在各个子模块中按需引入,子模块中只需要声明groupIdartifactId即可。

  1. kotlin-maven-lombok:处理kotlin代码转换与lombok注解处理的先后关系,没有它,如果在同一个模块中,kotlin代码里面用到了java代码中的类,而该类使用了lombok注解,那就会有问题。

  2. allopenkotlin中所有的类默认都是不可继承,spring框架的代理就不好使了。所以kotlin代码里会满满的open。这个插件可以省掉这些open,为指定注解注解的类在编译时添加open。以上面的配置为例,可以在compilerPluginsjvmTarget之间加上下面的配置,即可让被Entity注解所注解的类默认open

    1
    2
    3
    <pluginOptions>
    <option>all-open:annotation=javax.persistence.Entity</option>
    </pluginOptions>
  3. spring:这个其实就是已经指定一些spring常用注解来添加open。本质上也是依赖allopen插件的。该插件指定了以下注解: @Component@Async@Transactional@Cacheable 以及 @SpringBootTest。由于元注解的支持,标注有 @Configuration@Controller@RestController@Service 或者 @Repository 的类会自动打开,因为这些注解标注有元注解@Component

  4. no-arg:该插件为具有特定注解的类生成一个额外的零参数构造函数。这个生成的构造函数是合成的,因此不能从 javakotlin中直接调用,但可以使用反射调用。这允许Java Persistence API(JPA)实例化一个类,就算它从 kotlinjava的角度看没有无参构造函数。

  5. maven打包成功,但是本地直接点击IDEADebug/Run还是报错,类似于:

Lombok requires enabled annotation processing: Do you want to enable annotation processors?

​ 依次点击setting –> BuildExecutionDeployment –>Annotation Processors打开编辑页面,勾上Enable annotation processing前面的勾,保存后需要重启IDEA

C. 子模块pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.leuncle.demo</groupId>
<artifactId>Demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>demo-domain</artifactId>
<packaging>jar</packaging>
<name>demo-domain</name>

<dependencies>
<!-- service models -->
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>com.leuncle.demo</groupId>
<artifactId>demo-external</artifactId>
</dependency>

<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>

<!-- kotlin -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk7</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-common</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

每个子模块需要单独引入kotlin的依赖。