aboutsummaryrefslogtreecommitdiffhomepage
path: root/site/docs/migrate-maven.md
blob: cb918324357aa8609de3b2aa2ea34327873d6b52 (plain)
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
---
layout: documentation
title: Migrating from Maven to Bazel
---

# Migrating from Maven to Bazel

When migrating from any build tool to Bazel, it’s best to have both build
tools running in parallel until you have fully migrated your development team,
CI system, and any other relevant systems. You can run Maven and Bazel in the
same repository.

## Table of contents


*  [Before you begin](#before-you-begin)
*  [Differences between Maven and Bazel](#differences-between-maven-and-bazel)
*  [Migrate from Maven to Bazel:](#migrate-from-maven-to-bazel)
   *  [1. Create the WORKSPACE file](#1-workspace)
      *  [Guava project example](#guava-1)
   *  [2. Create one BUILD file](#2-build)
      *  [Guava project example](#guava-2)
   *  [3. Create more BUILD files  (Optional)](#3-build)
   *  [4. Build using Bazel](#4-build)

## Before you begin

*  [Install Bazel](install.md) if it’s not yet installed.
*  If you’re new to Bazel, go through the tutorial
   [Introduction to Bazel: Build Java](tutorial/java.md) before you start
   migrating. The tutorial explains Bazel’s concepts, structure, and label
   syntax.

## Differences between Maven and Bazel

*  Maven uses top-level `pom.xml` file(s). Bazel supports multiple build
   files and multiple targets per BUILD file, allowing for builds that
   are more incremental than Maven's.
*  Maven takes charge of steps for the deployment process. Bazel does
   not automate deployment.
*  Bazel enables you to express dependencies between languages.
*  As you add new sections to the project, with Bazel you may need to add new
   BUILD files. Best practice is to add a BUILD file to each new Java package.

## Migrate from Maven to Bazel

The steps below describe how to migrate your project to Bazel:

1.  [Create the WORKSPACE file](#1-workspace)
2.  [Create one BUILD file](#2-build)
3.  [Create more BUILD files](#3-build)
4.  [Build using Bazel](#4-build)

Examples below come from a migration of the
[Guava project](https://github.com/google/guava) from Maven to Bazel. The Guava
project used is release 22.0. The examples using Guava do not walk through
each step in the migration, but they do show the files and contents that are
generated or added manually for the migration.

### <a name="1-workspace"></a>1. Create the WORKSPACE file

Create a file named `WORKSPACE` at the root of your project. If your project
has no external dependencies, the workspace file can be empty.

If your project depends on files or packages that are not in one of the
project’s directories, specify these external dependencies in the workspace
file. To automate the listing of external dependencies for the workspace file,
use the tool `generate_workspace`. For instructions about using this tool, see
[Generate a WORKSPACE file for a Java project](generate-workspace.md).

#### <a name="guava-1"></a>Guava project example: external dependencies

Below are the results of using the tool `generate_workspace` to list the
[Guava project's](https://github.com/google/guava) external dependencies.

1.  The new `WORKSPACE` file contains:

    ```bash
    load("//:generate_workspace.bzl", "generated_maven_jars")
    generated_maven_jars()
    ```

2.  The new `BUILD` file in the directory `third_party` enables access
    to external libraries. This BUILD file contains:

    ```bash
    load("//:generate_workspace.bzl", "generated_java_libraries")
    generated_java_libraries()
    ```

3.  The generated `generate_workspace.bzl` file contains:

    ```bash
    # The following dependencies were calculated from:
    #
    # generate_workspace --maven_project=/usr/local/.../guava


    def generated_maven_jars():
      # pom.xml got requested version
      # com.google.guava:guava-parent:pom:23.0-SNAPSHOT
      native.maven_jar(
          name = "com_google_code_findbugs_jsr305",
          artifact = "com.google.code.findbugs:jsr305:1.3.9",
          sha1 = "40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf",
      )


      # pom.xml got requested version
      # com.google.guava:guava-parent:pom:23.0-SNAPSHOT
      native.maven_jar(
          name = "com_google_errorprone_error_prone_annotations",
          artifact = "com.google.errorprone:error_prone_annotations:2.0.18",
          sha1 = "5f65affce1684999e2f4024983835efc3504012e",
      )


      # pom.xml got requested version
      # com.google.guava:guava-parent:pom:23.0-SNAPSHOT
      native.maven_jar(
          name = "com_google_j2objc_j2objc_annotations",
          artifact = "com.google.j2objc:j2objc-annotations:1.1",
          sha1 = "ed28ded51a8b1c6b112568def5f4b455e6809019",
      )




    def generated_java_libraries():
      native.java_library(
          name = "com_google_code_findbugs_jsr305",
          visibility = ["//visibility:public"],
          exports = ["@com_google_code_findbugs_jsr305//jar"],
      )


      native.java_library(
          name = "com_google_errorprone_error_prone_annotations",
          visibility = ["//visibility:public"],
          exports = ["@com_google_errorprone_error_prone_annotations//jar"],
      )


      native.java_library(
          name = "com_google_j2objc_j2objc_annotations",
          visibility = ["//visibility:public"],
          exports = ["@com_google_j2objc_j2objc_annotations//jar"],
      )
  ```

### <a name="2-build"></a>2. Create one BUILD file

Now that you have your workspace defined and external dependencies (if
applicable) listed, you need to create BUILD files to describe how your project
should be built. Unlike Maven with its one `pom.xml` file, Bazel can use many
BUILD files to build a project. These files specify multiple build targets,
which allow Bazel to produce incremental builds.

Add BUILD files in stages. Start with adding one BUILD file
at the root of your project and using it to do an initial build using Bazel.
Then, you refine your build by adding more BUILD files with more granular
targets.

1.  In the same directory as your `WORKSPACE` file, create a text file and
    name it `BUILD`.

2.  In this BUILD file, use the appropriate rule to create one target to
    build your project. Here are some tips:
    *  Use the appropriate rule:
       *  To build projects with a single Maven module, use the
          `java_library` rule as follows:

          ```bash
          java_library(
              name = "everything",
              srcs = glob(["src/main/java/**/*.java"]),
              resources = glob(["src/main/resources/**"]),
              deps = ["//:all-external-targets"],
          )
          ```
       *  To build projects with multiple Maven modules, use the
          `java_library` rule as follows:

          ```bash
          java_library(
              name = "everything",
              srcs = glob([
                  "Module1/src/main/java/**/*.java",
                  "Module2/src/main/java/**/*.java",
                  ...
              ]),
              resources = glob([
                  "Module1/src/main/resources/**",
                  "Module2/src/main/resources/**",
                  ...
              ]),
              deps = ["//:all-external-targets"],
          )
          ```
       *  To build binaries, use the `java_binary` rule:

          ```bash
          java_binary(
              name = "everything",
              srcs = glob(["src/main/java/**/*.java"]),
              resources = glob(["src/main/resources/**"]),
              deps = ["//:all-external-targets"],
              main_class = "com.example.Main"
          )
          ```
    *  Specify the attributes:
       *  `name`: Give the target a meaningful name. In the examples above
          we call the target “everything.”
       *  `srcs`: Use globbing to list all .java files in your project.
       *  `resources`: Use globbing to list all resources in your project.
       *  `deps`: You need to determine which external dependencies your
          project needs. For example, if you generated a list of external
          dependencies using the tool `generate_workspace`, the dependencies
          for `java_library` are the libraries listed in the
          `generated_java_libraries` macro.
    *  Take a look at the
       [example below of this top-level BUILD file](#guava-example-2) from
       the migration of the Guava project.

3.  Now that you have a BUILD file at the root of your project, build
    your project to ensure that it works. On the command line, from your
    workspace directory, use `bazel build //:everything` to build your
    project with Bazel.

    The project has now been successfully built with Bazel. You will need
    to add more BUILD files to allow incremental builds of the project.

#### <a name="guava-2"></a>Guava project example: start with one BUILD file

When migrating the Guava project to Bazel, initially one BUILD file is used
to build the enitre project. Here are the contents of this initial `BUILD`
file in the workspace directory:

```bash
java_library(
    name = "everything",
    srcs = glob(["guava/src/**/*.java"]),
    deps = [
      "//third_party:com_google_code_findbugs_jsr305",
      "//third_party:com_google_errorprone_error_prone_annotations",
      "//third_party:com_google_j2objc_j2objc_annotations"
    ],
)
```

### <a name="3-build"></a>3. Create more BUILD files (Optional)

Bazel does work with just one BUILD file, as you saw after completing your first
build. You should still consider breaking the build into smaller chunks by
adding more BUILD files with granular targets.

Multiple BUILD files with multiple targets will give the build increased
granularity, allowing:

*  increased incremental builds of the project,
*  increased parallel execution of the build,
*  better maintainability of the build for future users, and
*  control over visibility of targets between packages, which can prevent
   issues such as libraries containing implementation details leaking into
   public APIs.

Tips for adding more BUILD files:

*  You can start by adding a BUILD file to each Java package. Start with
   Java packages that have the fewest dependencies and work you way up
   to packages with the most dependencies.
*  As you add BUILD files and specify targets, add these new targets to the
   `deps` sections of targets that depend on them. Note that the `glob()`
   function does not cross package boundaries, so as the number
   of packages grows the files matched by `glob()` will shrink.
*  Any time you add a BUILD file to a `main` directory, ensure that you add
   a BUILD file to the corresponding `test` directory.
*  Take care to limit visibility properly between packages.
*  To simplify troubleshooting errors in your setup of BUILD files, ensure
   that the project continues to build with Bazel as you add each build
   file. Run `bazel build //...` to ensure all of your targets still build.

### <a name="4-build"></a>4. Build using Bazel

You’ve been building using Bazel as you add BUILD files to validate the setup
of the build.

When you have BUILD files at the desired granularity, you can use Bazel
to produce all of your builds.