Checklist for Migrating from Vert.x 2.1.x to Vert.x 3 - Part One

This blog post presents feed­backs from a project mi­gra­tion using Vert.x 2 to Vert.x 3.

We are in the process of converting our Vert.x 2.1.5 application to Vert.x 3.0.

So while up­grad­ing our ap­pli­ca­tion, I thought I should note down all the changes that we had to do in the process. Since Vert.x 3 is a major up­grade from the pre­vi­ous ver­sion, with so many changes.

It re­quires re-​thinking your cur­rent 2.x Vert.x ap­pli­ca­tion. There are new classes, new apis, and a new pack­age struc­ture that has greatly sim­pli­fied things that we used to have to work around. There­fore in our up­grade it re­quired us to refac­tor and re­move any un­nec­es­sary “hacks” that weren’t avail­able in 2 that are now a part of Vert.x 3 that you re­ally want and need to take ad­van­tage of. (I don’t mean there are hacks in 3.x, just that we had in our ap­pli­ca­tion with Vert.x 2.x)

There are Met­rics, and Clus­tered shared data, with lock­ing and many more fea­tures that are amaz­ing new ad­di­tions. These are things we had to hack into our ap­pli­ca­tion with Vert.x 2.x. We added our own MetricsRegistry from Drop­Wiz­ard which meant mak­ing our own Main class that called Vert.x’s Starter class after start­ing up the reg­istry, but only in our De­vops server de­ploys, not our de­vel­oper ma­chines. And we had to build our own dis­trib­uted locked of clus­tered data that also re­quired writ­ing a com­pre­hen­sive dis­trib­uted timers. (The timers got fixed with a bet­ter actor model). But now we can use what Vert.x gives us in­ter­nally for those use cases.

This blog post is part one, as I am sure there will be some new changes that we need to do that we haven’t got­ten to yet. Which as we go, will post in part two. Also that this post is a work in progress in that when­ever you are up­grad­ing and refac­tor­ing your code, it doesn’t leave much time for tak­ing de­tailed notes, or writ­ing beau­ti­ful prose. I am a ter­ri­ble writer even when I can fully con­cen­trate on it. So the first draft will just be a list of my notes. These notes are not in any par­tic­u­lar order, but some things like tests you might want to save for last. (Just DON’T delete your tests, tests are very im­por­tant)

One of the first things that Vert.x has changed is the whole class­loader setup. Read the Vert.x Docs for more in­for­ma­tion but ba­si­cally, we have a flat class­loader sys­tem now. YAY! And one of the first things I no­ticed that is gone is the Platform mod­ule.

Changes we have made.

Dependency changes

  1. So the first thing we did was to re­move the vert.x-platform de­pen­dency from our pom file (Build de­pen­dency file of what­ever build sys­tem you use) This also means that you will be re­mov­ing any im­port state­ments from your code that has .platform. Which leads us to the next point.

  2. Change all the im­ports for Vertx. from org.vertx to io.vertx. This could be a lot of work, as it is in every class you use Vert.x in. We had at least 250 lo­ca­tions to change here. Some classes have moved pack­ages and “jars” that have them, so there will be some new jars to in­clude as de­pen­den­cies and dif­fer­ent im­port state­ments for them.

  3. If using a lan­guage other than Java, change the de­pen­dency to vertx-lang-<<language>>

  4. Re­move any mod­ules ref­er­ences that are using Vert.x 2.x stuff. You can get an odd error like The type org.vertx.java.core.json.JsonOb­ject can­not be re­solved. It is in­di­rectly ref­er­enced from re­quired .class files.

  5. testtools de­pen­dency is gone. There is now Vertx-​unit. So all your pre­vi­ous tests need to be com­pletely re-​written in the new style. This can be re­ally dif­fi­cult and time con­sum­ing as the tests you al­ready have writ­ten re­ally do need to be re-​written from scratch. But these tests are also the back­bone in know­ing if your code is work­ing. So this could take months if you have a re­ally full set of test suites al­ready. Also note the list below is to con­vert your JUnit In­te­gra­tion tests. as vertx-​unit first and fore­most pro­vides its own test­ing frame­work/suite but it also works in JUnit, and if you are using JUnit you need to do the fol­low­ing

  • Re­move all the im­ports to TestTools, in­clud­ing VertxAssert. I would do a find/re­place to re­place all the VertxAssert to testContext for when you have to add TestContext to all your @Test meth­ods. I rec­om­mend nam­ing the pa­ra­me­ter testContext, just to put more con­text, into your con­text. Be­cause if you just have context as your pa­ra­me­ter name, how do you know what con­text the con­text is? Sorry, that was too much fun. Ba­si­cally, what I am say­ing is if you have say Spring ApplicationContext in with your in­te­gra­tion tests with Vert.x what does context rep­re­sent? Spring or Vert.x test con­text.
  • Add @RunWith(VertxUnitRunner.class) above your test class
  • Re­move any VertxAssert.testComplete() those are gone. It needs TestContext.async().complete(). It is also im­por­tant to un­der­stand what async() means. When to call it, when to com­plete it. It also al­lows you to do mul­ti­ple async() calls and nested ones. I think I needed that when I had a test that was a longer use case of many mes­sages being sent, but only after re­sponses to other ones oc­curred. For in­stance, to do chat in our app, you have to con­nect, sub­scribe, friend some­one, then you can send a chat mes­sage. So that is 4 total Vert.x Mes­sages sent from the Test client. And you can sub­scribe until con­nect com­pleted, and you can send or re­ceive mes­sages un­less you are sub­scribed and have a friend. So we need to have a few async() calls in that sce­nario.
  • What is in your start method over­ride. Make that an @Before.
  • What is in your stop method over­ride. Make that an @After.
  • If you have your as­ser­tions have cus­tom mes­sage strings to log out when they fail, that pa­ra­me­ter is now at the end of the assert method call. Yes, this one can be painful.

Build Changes

  1. Re­move all vertx maven plugin code to gen­er­ate mod­ules, in­stead cre­ate fat jars, which re­quires adding the Shade maven plugin to put all jar files into a big fat jar. The vertx-​examples project has simplest-​maven which has the stuff to cre­ate the fat jar. simplest-​gradle is the gra­dle equiv­a­lent.

  2. If you were run­ning your ap­pli­ca­tion with runMod or some­thing like that then you need to cre­ate a fat jar, chang­ing the build file as in this one and cre­ate a Main class like here this one.

Class/Code Changes

  1. Verticle is now an in­ter­face and not a class to ex­tend, so using Groovy as an ex­am­ple you now ex­tend GroovyVerticle. In Java ex­tend AbstractVerticle in­stead.

  2. There is no registerHandler on the event­Bus any­more. So every­where you do that has to change to cre­ate/call consumer() and to un­reg­is­ter that han­dler, you have to have a ref­er­ence to the MessageConsumer that consumer() call re­turns and call its unregister method.

  3. JsonObject.toMap() changed to JsonObject.getMap()

  4. JsonObject also re­moved all the putXXX meth­ods with just one put method with over­loaded ver­sions for dif­fer­ent types.

  5. JsonObjectMessage no longer ex­ists. What re­places de­pends on what you are doing. Mean­ing, if it is an async call­back to a de­ploy, you will get a Message in­stance back that has succeeded() or failed() meth­ods as well as body() to check any re­sults. If it is a Consumer, it is typ­i­cally a straight for­ward JsonObject. If you are in Groovy it is also a JsonObject, but the body() is a Map which you can use di­rectly now, in­stead of hav­ing to con­vert from JsonObject to Map.

  6. There isn’t a container vari­able in Verticles any­more for de­ploy­ing ver­ti­cles and also a con­fig file. You need to use vertx.getOrCreateContext().config() to get to it. I used that in the SockJS Ex­am­ple code below.

  7. SharedData no longer has shared sets. It has a Map of SharedData, so an entry in that Map of shared data could be the name of the set as the key, and a Set as the value. It ac­tu­ally gives you more flex­i­bil­ity of what you put into Shared data, so this is ac­tu­ally a big win for us.

  8. Get­ting the writeHandlerID from a Socket type, is now a method call in­stead of .writeHandlerID, so .writeHandlerID()

  9. SockJSSocket is in vertx-​web pack­age now, so in­clude it to get the class.

  10. There isn’t a SockJSServer class any­more ei­ther. So you will cre­ate a WebServer, a Router and set SSL (if you are using SSL on the Web­Server) then cre­ate a SockJSHandler to as­sign to the router via the route() method and handler() meth­ods in the Router api. Here is an ex­am­ple of our code. Al­though I haven’t tested it yet. ;)

public class MyVerticle extends GroovyVerticle {
  Router router

  @Override
  void start() throws Exception {
     router = Router.router(vertx)
     (Map<String, Object>) sslConfig =
        (Map<String, Object>)vertx.getOrCreateContext()
          .config().get('ssl')

     HttpServer sslHttpServer = vertx.createHttpServer(
         SSL: true,
         keyStorePath: sslConfig.get("keystore"),
         keyStorePassword: sslConfig.get("password"))

     startWebApiServer(sslHttpServer)
  }

  private void startWebApiServer(final HttpServer httpServer) {
    def sockHandler = SockJSHandler.create(vertx, [:])
    sockHandler.socketHandler {
      SockJSSocket ws -> sockJSConnectHandler(ws)
    }
    router.route("/hdpoker").handler(sockHandler)
    httpServer.requestHandler(router.&accept)
    httpServer.listen()
  }

}

More testing change

Test­ing mes­sages in In­te­gra­tion Tests. To tell the test method that this has async calls put Async async = testContext.async() as the first line in the test method. Yes, this is a lit­tle re­dun­dant from above, but I al­ways for­got to put async() calls in my in­te­gra­tion tests and they would pass so quickly, with­out send­ing any­thing out, be­cause it wasn’t wait­ing any­more

Runtime changes

If you don’t use Vert.x built-​in Log­ging and need to use slf4j, then re­mem­ber that you should set a sys­tem prop­erty called vertx.logger-delegate-factory-class-name with the name of a Java class which im­ple­ments the in­ter­face LoggerFactory. Vert.x pro­vides pre-​built im­ple­men­ta­tions for Log4J and SLF4J with the class names io.vertx.core.logging.Log4jLogDelegateFactory and io.vertx.core.logging.SLF4JLogDelegateFactory.

Still working

Well, that is all I have for you folks so far. We are still not done, as we haven’t got­ten our ap­pli­ca­tion run­ning with real clients just yet. But we do have all our in­te­gra­tion tests from be­fore com­pletely pass­ing so, if some­thing does come up, it should be a small one (KNOCK ON WOOD)

Please feel free to post on the Vert.x Google Group with any com­ments or sug­ges­tions on what to add to this blog post or for Part Two.

Thanks

Mark S

Next post

Vert.x 3 says “hello” to NPM users

In programming literature it has become the standard to create a hello world program as the first example. In this article, I'll demonstrate how NPM users can quickly get started with Vert.x.

Read more
Previous post

Vert.x 3 and PostgreSQL JSON type

One of the interesting features of NoSQL databases is their schema-less mode of operation. This feature is very useful during project prototyping and early development since at early the stages of development of projects all data structures are not clear or have been defined yet.

Read more
Related posts

Unit and Integration Tests

Let’s refresh our mind about what we developed so far in the introduction to vert.x series. We forgot an important task. We didn’t test the API.

Read more

My first Vert.x 3 Application

Let's say, you heard someone saying that Vert.x is awesome. Ok great, but you may want to try it by yourself. Well, the next natural question is “where do I start ?”

Read more

Using the asynchronous SQL client

Finally, back... This post is the fifth post of the introduction to vert.x blog series, after a not-that-small break. In this post we are going to see how we can use JDBC in a vert.x application.

Read more