blob: 06965a0353a4211d767f3115bde974f2a8d77d61 [file] [log] [blame] [view]
Googler7b30d752017-07-17 16:35:17 +02001---
2layout: documentation
3title: Migrating from Maven to Bazel
4---
5
6# Migrating from Maven to Bazel
7
8When migrating from any build tool to Bazel, it’s best to have both build
9tools running in parallel until you have fully migrated your development team,
10CI system, and any other relevant systems. You can run Maven and Bazel in the
11same repository.
12
13## Table of contents
14
15
16* [Before you begin](#before-you-begin)
17* [Differences between Maven and Bazel](#differences-between-maven-and-bazel)
18* [Migrate from Maven to Bazel:](#migrate-from-maven-to-bazel)
19 * [1. Create the WORKSPACE file](#1-workspace)
20 * [Guava project example](#guava-1)
21 * [2. Create one BUILD file](#2-build)
22 * [Guava project example](#guava-2)
Googleref1424c2017-08-30 00:03:42 +020023 * [3. Create more BUILD files (Optional)](#3-build)
Googler7b30d752017-07-17 16:35:17 +020024 * [4. Build using Bazel](#4-build)
25
26## Before you begin
27
28* [Install Bazel](install.md) if it’s not yet installed.
29* If you’re new to Bazel, go through the tutorial
30 [Introduction to Bazel: Build Java](tutorial/java.md) before you start
31 migrating. The tutorial explains Bazel’s concepts, structure, and label
32 syntax.
33
34## Differences between Maven and Bazel
35
36* Maven uses top-level `pom.xml` file(s). Bazel supports multiple build
37 files and multiple targets per BUILD file, allowing for builds that
38 are more incremental than Maven's.
39* Maven takes charge of steps for the deployment process. Bazel does
40 not automate deployment.
41* Bazel enables you to express dependencies between languages.
42* As you add new sections to the project, with Bazel you may need to add new
43 BUILD files. Best practice is to add a BUILD file to each new Java package.
44
45## Migrate from Maven to Bazel
46
47The steps below describe how to migrate your project to Bazel:
48
491. [Create the WORKSPACE file](#1-workspace)
502. [Create one BUILD file](#2-build)
513. [Create more BUILD files](#3-build)
524. [Build using Bazel](#4-build)
53
54Examples below come from a migration of the
55[Guava project](https://github.com/google/guava) from Maven to Bazel. The Guava
56project used is release 22.0. The examples using Guava do not walk through
57each step in the migration, but they do show the files and contents that are
58generated or added manually for the migration.
59
60### <a name="1-workspace"></a>1. Create the WORKSPACE file
61
62Create a file named `WORKSPACE` at the root of your project. If your project
63has no external dependencies, the workspace file can be empty.
64
65If your project depends on files or packages that are not in one of the
66project’s directories, specify these external dependencies in the workspace
67file. To automate the listing of external dependencies for the workspace file,
jingwen15fe5fa2019-04-26 10:28:18 -070068use `rules_jvm_external`. For instructions about using this ruleset, see
69[the README](https://github.com/bazelbuild/rules_jvm_external/#rules_jvm_external).
70
71> NOTE: The previously recommend tool, `generate_workspace`, is no longer
72maintained by the Bazel team.
Googler7b30d752017-07-17 16:35:17 +020073
74#### <a name="guava-1"></a>Guava project example: external dependencies
75
jingwen15fe5fa2019-04-26 10:28:18 -070076Using the `rules_jvm_external` ruleset, we can list the external dependencies of
77the [Guava project](https://github.com/google/guava)
Googler7b30d752017-07-17 16:35:17 +020078
jingwen15fe5fa2019-04-26 10:28:18 -070079Add the following snippet to the `WORKSPACE` file:
Googler7b30d752017-07-17 16:35:17 +020080
jingwen13b08a62019-04-30 14:40:58 -070081```python
82load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
jingwen15fe5fa2019-04-26 10:28:18 -070083
jingwen13b08a62019-04-30 14:40:58 -070084RULES_JVM_EXTERNAL_TAG = "2.0.1"
85RULES_JVM_EXTERNAL_SHA = "55e8d3951647ae3dffde22b4f7f8dee11b3f70f3f89424713debd7076197eaca"
jingwen15fe5fa2019-04-26 10:28:18 -070086
jingwen13b08a62019-04-30 14:40:58 -070087http_archive(
88 name = "rules_jvm_external",
89 strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
90 sha256 = RULES_JVM_EXTERNAL_SHA,
91 url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
92)
jingwen15fe5fa2019-04-26 10:28:18 -070093
jingwen13b08a62019-04-30 14:40:58 -070094load("@rules_jvm_external//:defs.bzl", "maven_install")
jingwen15fe5fa2019-04-26 10:28:18 -070095
jingwen13b08a62019-04-30 14:40:58 -070096maven_install(
97 artifacts = [
98 "com.google.code.findbugs:jsr305:1.3.9",
99 "com.google.errorprone:error_prone_annotations:2.0.18",
100 "com.google.j2objc:j2objc-annotations:1.1",
101 ],
102 repositories = [
103 "https://jcenter.bintray.com/",
104 "https://repo1.maven.org/maven2",
105 ],
106)
107```
Googler7b30d752017-07-17 16:35:17 +0200108
Googler7b30d752017-07-17 16:35:17 +0200109### <a name="2-build"></a>2. Create one BUILD file
110
111Now that you have your workspace defined and external dependencies (if
112applicable) listed, you need to create BUILD files to describe how your project
113should be built. Unlike Maven with its one `pom.xml` file, Bazel can use many
114BUILD files to build a project. These files specify multiple build targets,
115which allow Bazel to produce incremental builds.
116
117Add BUILD files in stages. Start with adding one BUILD file
118at the root of your project and using it to do an initial build using Bazel.
119Then, you refine your build by adding more BUILD files with more granular
120targets.
121
1221. In the same directory as your `WORKSPACE` file, create a text file and
123 name it `BUILD`.
124
1252. In this BUILD file, use the appropriate rule to create one target to
126 build your project. Here are some tips:
127 * Use the appropriate rule:
128 * To build projects with a single Maven module, use the
129 `java_library` rule as follows:
130
jingwen13b08a62019-04-30 14:40:58 -0700131 ```python
Googler7b30d752017-07-17 16:35:17 +0200132 java_library(
133 name = "everything",
134 srcs = glob(["src/main/java/**/*.java"]),
135 resources = glob(["src/main/resources/**"]),
136 deps = ["//:all-external-targets"],
137 )
138 ```
139 * To build projects with multiple Maven modules, use the
140 `java_library` rule as follows:
141
jingwen13b08a62019-04-30 14:40:58 -0700142 ```python
Googler7b30d752017-07-17 16:35:17 +0200143 java_library(
144 name = "everything",
145 srcs = glob([
146 "Module1/src/main/java/**/*.java",
147 "Module2/src/main/java/**/*.java",
148 ...
149 ]),
150 resources = glob([
151 "Module1/src/main/resources/**",
152 "Module2/src/main/resources/**",
153 ...
154 ]),
155 deps = ["//:all-external-targets"],
156 )
157 ```
158 * To build binaries, use the `java_binary` rule:
159
jingwen13b08a62019-04-30 14:40:58 -0700160 ```python
Googler7b30d752017-07-17 16:35:17 +0200161 java_binary(
162 name = "everything",
163 srcs = glob(["src/main/java/**/*.java"]),
164 resources = glob(["src/main/resources/**"]),
165 deps = ["//:all-external-targets"],
166 main_class = "com.example.Main"
167 )
168 ```
169 * Specify the attributes:
170 * `name`: Give the target a meaningful name. In the examples above
171 we call the target “everything.”
172 * `srcs`: Use globbing to list all .java files in your project.
173 * `resources`: Use globbing to list all resources in your project.
174 * `deps`: You need to determine which external dependencies your
175 project needs. For example, if you generated a list of external
176 dependencies using the tool `generate_workspace`, the dependencies
Googlerd40b74a2017-08-10 22:12:28 +0200177 for `java_library` are the libraries listed in the
Googler7b30d752017-07-17 16:35:17 +0200178 `generated_java_libraries` macro.
179 * Take a look at the
180 [example below of this top-level BUILD file](#guava-example-2) from
181 the migration of the Guava project.
182
1833. Now that you have a BUILD file at the root of your project, build
184 your project to ensure that it works. On the command line, from your
185 workspace directory, use `bazel build //:everything` to build your
186 project with Bazel.
187
188 The project has now been successfully built with Bazel. You will need
189 to add more BUILD files to allow incremental builds of the project.
190
191#### <a name="guava-2"></a>Guava project example: start with one BUILD file
192
193When migrating the Guava project to Bazel, initially one BUILD file is used
rachcatchedb96a52018-11-01 07:32:31 -0700194to build the entire project. Here are the contents of this initial `BUILD`
Googler7b30d752017-07-17 16:35:17 +0200195file in the workspace directory:
196
jingwen13b08a62019-04-30 14:40:58 -0700197```python
Googler7b30d752017-07-17 16:35:17 +0200198java_library(
199 name = "everything",
200 srcs = glob(["guava/src/**/*.java"]),
201 deps = [
jingwen15fe5fa2019-04-26 10:28:18 -0700202 "@maven//:com_google_code_findbugs_jsr305",
203 "@maven//:com_google_errorprone_error_prone_annotations",
204 "@maven//:com_google_j2objc_j2objc_annotations"
Googler7b30d752017-07-17 16:35:17 +0200205 ],
206)
207```
208
Googleref1424c2017-08-30 00:03:42 +0200209### <a name="3-build"></a>3. Create more BUILD files (Optional)
Googler7b30d752017-07-17 16:35:17 +0200210
Googleref1424c2017-08-30 00:03:42 +0200211Bazel does work with just one BUILD file, as you saw after completing your first
212build. You should still consider breaking the build into smaller chunks by
213adding more BUILD files with granular targets.
Googler7b30d752017-07-17 16:35:17 +0200214
Googleref1424c2017-08-30 00:03:42 +0200215Multiple BUILD files with multiple targets will give the build increased
216granularity, allowing:
217
218* increased incremental builds of the project,
219* increased parallel execution of the build,
220* better maintainability of the build for future users, and
221* control over visibility of targets between packages, which can prevent
222 issues such as libraries containing implementation details leaking into
223 public APIs.
Googler7b30d752017-07-17 16:35:17 +0200224
225Tips for adding more BUILD files:
226
Akira Baruah4cf32b02017-11-03 19:40:20 +0100227* You can start by adding a BUILD file to each Java package. Start with
Googler7b30d752017-07-17 16:35:17 +0200228 Java packages that have the fewest dependencies and work you way up
229 to packages with the most dependencies.
230* As you add BUILD files and specify targets, add these new targets to the
231 `deps` sections of targets that depend on them. Note that the `glob()`
232 function does not cross package boundaries, so as the number
233 of packages grows the files matched by `glob()` will shrink.
234* Any time you add a BUILD file to a `main` directory, ensure that you add
235 a BUILD file to the corresponding `test` directory.
236* Take care to limit visibility properly between packages.
237* To simplify troubleshooting errors in your setup of BUILD files, ensure
238 that the project continues to build with Bazel as you add each build
239 file. Run `bazel build //...` to ensure all of your targets still build.
240
Googler7b30d752017-07-17 16:35:17 +0200241### <a name="4-build"></a>4. Build using Bazel
242
243You’ve been building using Bazel as you add BUILD files to validate the setup
244of the build.
245
246When you have BUILD files at the desired granularity, you can use Bazel
247to produce all of your builds.