Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time

RMB upgrading notes

These are notes to assist upgrading to newer versions. See the NEWS summary of changes for each version.

Version 34.0


RMB starts with default value of MaxFormAttributeSize of 8192, rather than 32768. Modules that rely on higher value, such as mod-login-saml, should set proper value in InitAPI hook.

   public void init(Vertx vertx, Context context, Handler<AsyncResult<Boolean>> handler) {
     RestVerticle.getHttpServerOptions().setMaxFormAttributeSize(64 * 1024);


UtilityClassTester no longer part of RMB. Use UtilityClassTester from okapi-testing. It has same API. Just import org.folio.okapi.testing.UtilityClassTester and extend pom.xml with:



TenantLoading methods addJsonIdContent and addJsonIdBasename are removed.


The PostgresClient.streamGet method without PostgresClientStreamResult parameter has been removed because it doesn't return totalCount and consumes too much memory. Use one of the other PostgresClient.streamGet methods with PostgresClientStreamResult.

PostgresClient.get methods with String where or String filter parameter have been removed to reduce SQL injection issues. Use PostgresClient.get methods with CQLWrapper or Criterion parameter instead.


The format of metadata.createdDate and metadata.updatedDate has changed.


"metadata": {
  "createdDate": "2020-10-19T09:31:31.529",
  "updatedDate": "2020-10-19T09:31:31.529+00:00",
  "createdByUserId": "ba6baf95-bf14-4020-b44c-0cad269fb5c9",
  "updatedByUserId": "ba6baf95-bf14-4020-b44c-0cad269fb5c9"


"metadata": {
  "createdDate": "2020-10-19T09:31:31.529Z",
  "updatedDate": "2020-10-19T09:31:31.529Z",
  "createdByUserId": "ba6baf95-bf14-4020-b44c-0cad269fb5c9",
  "updatedByUserId": "ba6baf95-bf14-4020-b44c-0cad269fb5c9"

This may cause some unit tests to fail, use java.time.Instant and compare Instants to be format agnostic.


Unit tests that pass X-Okapi-Tenant header into TenantTool.tenantId must use a case insensitive map. Replace Map.of("x-okapi-tenant", "foo") with new CaseInsensitiveMap<>(Map.of("x-okapi-tenant", "foo")) after import This avoids failures caused by fall-back tenant id folio_shared.

Version 33.2

RMB-718, FOLIO-3351

If the module intends to adopt the new totalRecords query parameter as part of this upgrade then update the submodule that sources to the latest version.

This is an optional step and NOT required to upgrade to 33.2, it is only necessary for using the new parameter.

This removes the language trait and adds totalRecords to the pageable trait:

Therefore you need to change the parameters of your methods that implement the RAML generated interfaces - remove the lang parameter, and add the String totalRecords parameter before the int offset parameter. The compile will fail unless this is done.



public void getMyitems(String query, int offset, int limit, String lang, Map<String, String> okapiHeaders,


public void getMyitems(String query, String totalRecords, int offset, int limit, Map<String, String> okapiHeaders,


public void postMyitems(String lang, Myitem entity, Map<String, String> okapiHeaders,


public void postMyitems(Myitem entity, Map<String, String> okapiHeaders,

Version 33.1

RMB-862, RMB-874 Upgrade to Vert.x 4.1.2/4.1.4

RMB 33.1.0 requires Vert.x 4.1.2 and okapi-common 4.8.2. RMB >= 33.1.1 requires Vert.x >= 4.1.3 and okapi-common >= 4.9.0.

Module should use vertx-stack-depchain:


The FOLIO fork of the vertx-sql-client and vertx-pg-client is no longer needed because our fix has been merged upstream for Vert.x >= 4.1.1.

Therefore remove these dependencies from the pom.xml:


Version 33.0

Module should use the vertx, netty, jackson and tcnative dependencies from vertx-stack-depchain to avoid old version with security vulnerabilities: Either remove the explicit vertx, netty, jackson and tcnative dependencies from the pom.xml or use the versions that vertx-stack-depchain` ships with, for example:


RMB-717 Deprecate HttpClientInterface, HttpModuleClient2, HttpClientMock2

All classes in are deprecated. Instead use the generated client provided by RMB or use WebClient directly. Tests can create HTTP servers with Vertx.createHttpServer or use other mocking facility.

RMB-789 Remove support of Embedded PostgreSQL Server

Removed support for embedded Postgres for testing. Testing is now with Testcontainers.

The following calls have been removed:

  • PostgresClient.setIsEmbedded
  • PostgresClient.setEmbeddedPort
  • PostgresClient.getEmbeddedPort

Enable testing with postgres by calling PostgresClient.setPostgresTester(new PostgresTesterContainer()) before any calls to PostgresClient or the Verticle. It is also possible to provide your own by implemeting the PostgresTester interface.

If DB_* environment variable database configuration (or JSON DB config) is provided, the PostgresTester instance is not used for testing. This allows testing to be performed on local Postgres instance. See RMB-826.

PostgresClient.stopEmbeddedPostgres replaced with PostgresClient.stopPostgresTester. The invocation is usually not needed and should be removed because PostgresClient and Testcontainers core will automatically close and remove the container.

PostgresClient.startEmbeddedPostgres replaced with PostgresClient.startPostgresTester. It is usually not necessary to invoke this as it is automatically called by PostgresClient when an instance is created.

Command-line option embed_postgres=true is no longer supported.

Remove <groupId></groupId> <artifactId>postgresql-embedded</artifactId> from pom.xml.

Remove loading db conf from url

Removed for security. Use DB_* environment variables instead. See discussion of RMB-855.

RMB-785 domain-models-maven-plugin

In pom.xml replace the exec-maven-plugin sections that call <mainClass></mainClass> by :


Replace <mainClass></mainClass> by a call to the same plugin. It must be used in a separate project depending on the artifact with generated interfaces.


If you need to set system properties for domain-models-maven-plugin run properties-maven-plugin with goal set-system-properties before:

Add FOLIO Maven repository for plugins after existing <repositories> section:

      <name>FOLIO Maven repository</name>

Remove domain-models-interface-extensions dependency from pom.xml.

Replace PomReader.INSTANCE.getModuleName() by ModuleName.getModuleName().

Replace PomReader.INSTANCE.getVersion() by ModuleName.getModuleVersion().

Replace PomReader.INSTANCE.getRmbVersion() by RmbVersion.getRmbVersion().

Replace any joda class usage by a java.time class usage. RMB no longer ships with joda-time that is deprecated because the replacement java.time has been in JDK core since Java 8.

Add commons-lang:commons-lang:2.6 dependency to pom.xml if commons-lang is used. RMB no longer ships with commons-lang.

Add org.assertj test dependency to pom.xml if Assertj is used. RMB no longer ships with Assertj.

Version 32.0

  • RMB-609 Upgrade to Vert.x 4:
    • Replace deprecated io.vertx.core.logging.Logger by org.apache.logging.log4j.Logger, for example private static final Logger LOGGER = LogManager.getLogger(Foo.class) (using getLogger() without argument requires Multi-Release for stack walking, see below).
    • Replace HttpClient .getAbs, .postAbs, .putAbs, .deleteAbs by WebClient.requestAbs(HttpMethod method, ...).
    • Replace Future.setHandler by Future.onComplete.
    • Future has been split into Future and Promise, see Futurisation in Vert.x 4.
    • The handlers of the autogenerated clients (generated by ClientGenerator) should be migrated from Handler to Handler<AsyncResult<HttpResponse>>
  • OKAPI-943 When calling .any, .all or .join replace io.vertx.core.CompositeFuture by org.folio.okapi.common.GenericCompositeFuture, replace raw type by actual type and remove @SuppressWarnings("rawtypes").
  • RMB-728 In pom.xml update aspectj-maven-plugin <configuration> with <complianceLevel>11</complianceLevel>.
  • Remove setWorker(true) when starting RestVerticle in tests or production code, learn why at RMB RestVerticle and MODINVSTOR-635.
  • Tenant API changed - refer to RAML. Tenant interface 2.0 is supported by Okapi 4.5.0 and later. RMB 32, thus, will not work with an earlier version of Okapi. If module includes the shared raml as a Git sub module, it should be updated as well. See issues FOLIO-2908 and FOLIO-2877 The API for purge, upgrade, init is single end-point. Client code (mostly testing code) must be able to handle both 201 with a Location and 204 No content if testing via HTTP. However, for API testing RMB 32.1.0 provides a simpler call: TenantAPI.postTenantSync. Update the module descriptor - usually descriptors/ModuleDescriptor-template.json - to tenant interface version 2. Replace the old _tenant "provides" with
    "provides" : [ {
       "id" : "_tenant",
       "version" : "2.0",
       "interfaceType" : "system",
       "handlers" : [ {
         "methods" : [ "POST" ],
         "pathPattern" : "/_/tenant"
       }, {
         "methods" : [ "GET", "DELETE" ],
         "pathPattern" : "/_/tenant/{id}"
       } ]
    } ]

Version 31.0

  • RMB-738 Since RMB 30.2.9 and 31.1.3: Upgrade to Vert.x 3.9.4
  • RMB-740 Since RMB 30.2.9 and 31.1.3: Use FOLIO fork of vertx-sql-client and vertx-pg-client, example pom.xml:
  • RMB-328 Update to OpenJDK 11. In most cases no code changes are necessary. A few files needs updating (mod-inventory-storage example):
    • pom.xml: For maven-compiler-plugin update version to 3.8.1 and use <release>11</release> instead of source and target elements.
    • pom.xml: Update aspectj version to 1.9.6. Update aspectj-maven-plugin with groupId com.nickwongdev and version 1.12.6 and set <complianceLevel>11</complianceLevel> in the <configuration> section.
    • Jenkinsfile: Add buildNode = 'jenkins-agent-java11'
    • Dockerfile (if present): change folioci/alpine-jre-openjdk8:latest to folioci/alpine-jre-openjdk11:latest.
    • docker/ remove if present.
    • For pom.xml, plugin maven-shade-plugin, add <Multi-Release>true</Multi-Release> to section manifestEntries. see this example. Also, after version element, add section as shown below to avoid warnings about format specifiers during startup. See this example.
  • A colon has been added to the timezone to comply with RFC 3339, 2017-07-27T10:23:43.000+0000 becomes 2017-07-27T10:23:43.000+00:00.

Version 30.2

  • RMB-652 error message "may not be null" changed to "must not be null" (hibernate-validator)
  • RMB-693 If using PostgresClient#selectStream always call RowStream#close.
  • RMB-702 Rename {version} path variable in RAML files.

Version 30.0

  • RMB-246 Switch to vertx-pg-client.
    • All functions that previously returned UpdateResult now return RowSet<Row>. From that result, the number of rows affected by SQL was getUpdated(), it is now rowCount().
    • All functions that previously returned ResultSet now return RowSet<Row>. From that result, the number of rows affected by SQL is rowCount(). The size() method returns number of rows returned. An iterator to go through rows is obtained by calling iterator().
    • PostgresClient.selectSingle returns Row rather than JsonArray.
    • PostgreSQL JSONB type was previously represented by Java String, now by Java JsonObject (return type and parameter type).
    • PostgreSQL UUID type (used for id and foreign keys columns) was previously represented by Java String, now by Java UUID (return type and parameter type).
    • In prepared/parameterized queries replace '?' signs by '$1', '$2' and so on and the parameters argument type JsonArray by Tuple.
    • Class SQLConnection is now provided by RMB. The same class name was used for the SQL client. io.vertx.ext.sql.SQLConnection ->
    • PostgresClient.getClient() is no longer public. If you need a connection, use PostgresClient.startTx(). For modules that wish to use vertx-pg-client directly, PostgresClient.getConnection is offered - it returns PgConnection from the pool that is managed by PostgresClient.
    • Replace exception.getMessage by PgExceptionUtil.getMessage(exception) to mimic the old GenericDatabaseException.getMessage(e) because the new PgException.getMessage(e) returns the message field only, no SQL error code, no detail.
    • PgExceptionFacade.getTable removed.
    • PgExceptionFacade.getIndex removed.
    • PgExceptionFacade.selectStream without SQLConnection has been removed. Streams must be executed within a transaction.
    • PostgresClient.mutate removed (deprecated since Oct 2018).
  • RMB-619 Deprecation due to upgrading to Vert.x 3.9:
    • Replace Verticle#start(Future<Void>) and Verticle#stop(Future<Void>) by Verticle#start(Promise<Void>) and Verticle#stop(Promise<Void>)
    • Replace Future.setHandler(ar -> …) by Future.onComplete(ar -> …)
  • Vert.x 4 will split Future into Future and Promise, see for details and deprecations.
  • RMB-624 Fix invalid RAML sample JSON files, otherwise GenerateRunner/SchemaDereferencer will fail with InvocationTargetException/DecodeException "Failed to decode". Hint: Use for i in *; do jq empty $i || echo $i; done to list invalid JSONs.
  • Update Vert.x to 3.9.1, consider using Vert.x Bill of Materials (Maven BOM) (content: vertx-dependencies pom.xml) for io.vertx:*, com.fasterxml.jackson.core:* and com.fasterxml.jackson.dataformat:* dependencies. Remove jackson-databind dependency from pom.xml if module doesn't use it directly.

Version 29.5

  • RMB-587 Write access to public schema has been removed, it is no longer in search_path and should be used for Postgres extensions only, prepend public. when calling their methods and operators. Example: RMB replaces gin_trgm_ops by public.gin_trgm_ops in indexes that RMB maintains.
  • RMB-588 Consider removing <directory>src/main/resources</directory> <filtering>true</filtering> from pom.xml (or use a more specific directory tree). For details see FOLIO-2548.
  • RMB-594 RMB no longer uses a random order, but a fixed order to generate the .java classes from the .raml and .json files. This may consistently fail the build if two classes with the same name are generated. To prevent the second from overwriting the first, set a different class name using "javaType": "". For example for link-field "folio:isVirtual" annotations for mod-graphql.

Version 29.2

  • RMB-532 Use PostgresClient.get without the unused and deprecated setId parameter.

Version 29

  • RMB-529 The update to Vert.x 3.8.4 deprecates several elements, including Json#mapper, Json#prettyMapper and Json#decodeValue: 3.8.2 Deprecations, 3.8.3 Deprecations

  • RMB-510 Tenant POST /_/tenant must include a body. Client that used an empty request must now include a body with at least: {"module_to":"module-id"}. This means that for modules that are using that previously passed null as for must now create TenantAttributes with moduleTo property.

  • RMB-497 removed PostgresClient.join methods. It also deprecates all PostgresClient.get methods taking where-clause strings. Module users should use Criterion or CQLWrapper instead to construct queries:

    • Remove Criterion.selects2String, Criterion.from2String
    • Remove Criteria.setJoinON, Criteria.isJoinON
    • CQLWrapper.toString no longer returns leading blank/space
  • RMB-514 Update aspectj-maven-plugin to version 11 and its aspectjrt and aspectjtools versions to 1.9.4 in pom.xml (example) to avoid "bad version" warnings.

Version 28

  • RMB-485 changed the postgresql driver. Namespace prefix change com.github.mauricio.async.db.postgresql to com.github.jasync.sql.db.postgresql

    • returns Map<Character.String> rather than Map<Object,String>

    • returns Map<Character,String> rather than Map<Object,String>

  • RMB-462 removed support for fullText defaultDictionary property (simple, english, german, etc.) in schema.json

Version 27.1

  • Remove each foreign key field index and each primary key field id index and uniqueIndex, by setting "tOps": "DELETE" in schema.json. These btree indexes are created automatically.
  • Each fullTextIndex that was created with a dictionary different than 'simple' (for example using to_tsvector('english', jsonb->>'foo')) needs to be dropped. Then RMB will recreate the index with 'simple'. Example:
  "scripts": [
      "run": "before",
      "fromModuleVersion": "10.0.1",
      "snippet": "DROP INDEX IF EXISTS loan_userid_idx_ft;"
  • Breaking change due to upgrading to Vert.x 3.8.1
    • old: vertx.executeBlocking(future -> …, result -> …);
    • new: vertx.executeBlocking(promise -> …, result -> …);
    • old: vertx.executeBlocking((Future <String> future ) -> …, result -> …);
    • new: vertx.executeBlocking((Promise<String> promise) -> …, result -> …);
  • Deprecation changes due to upgrading to Vert.x 3.8.1
    • old: Future <String> fut = Future.future(); … return fut;
    • new: Promise<String> promise = Promise.promise(); … return promise.future();
    • old: AbstractVerticle start(Future <Void> fut)
    • new: AbstractVerticle start(Promise<Void> fut)
    • old: future.compose(res -> …, anotherFuture);
    • new: future.compose(res -> { …; return anotherFuture; });
  • Deprecation changes due to upgrading to Vert.x 3.8.1 > 3.6.2
    • old: HttpClient request/response methods with Handler<HttpClientResponse>
    • new: WebClient request/response methods with Handler<AsyncResult<HttpClientResponse>>

Version 27

  • Update the raml-util subdirectory to the latest raml1.0 commit of to make metadata.createdByUserId optional:
    • Hint: cd ramls/raml-util; git fetch; git checkout 69f6074; cd ../..; git add ramls/raml-util
    • Note that pom.xml may revert any submodule update that hasn't been staged or committed! (See notes.)

Version 26

  • The audit (history) table changed to a new incompatible schema. New audit configuration options are required in schema.json. See for details.
  • PostgresClient constructor now, by default, starts Embedded Postgres. This means that if you have unit tests that do not start Embedded Postgres explicitly, you might need to terminate Embedded Postgres by calling PostgresClient.stopEmbeddedPostgres

Version 25

  • Remove any "pkColumnName", "generateId" and "populateJsonWithId" entries in src/main/resources/templates/db_scripts/schema.json.
    • Hint: grep -v -e '"pkColumnName"' -e '"generateId"' -e '"populateJsonWithId"' < schema.json >, review, mv schema.json
  • In Java files change cql2pgjson import statements:
    • old: import org.z3950.zing.cql.cql2pgjson.CQL2PgJSON;
    • old: import org.z3950.zing.cql.cql2pgjson.FieldException;
    • new: import org.folio.cql2pgjson.CQL2PgJSON;
    • new: import org.folio.cql2pgjson.exception.FieldException;
  • In Java files replace any Criteria.setValue.
    • Consider using some method or some PostgresClient method that takes a CQL query or an id because those methods have optimizations that Criteria doesn't have.
    • If you still want to use Criteria please note that setVal does both quoting and masking.
    • old: setValue(s) // prone to SQL injection
    • old: setValue("'" + s + "'") // prone to SQL injection
    • old: setValue("'" + s.replace("'", "''") + "'")
    • new: setVal(s)
  • In SQL code replace _id (or whatever you used as pkColumnName) by id.
  • In SQL code remove gen_random_uuid() and generate the UUID before sending the query to the database, for example with Java's UUID.randomUUID(). This is needed because gen_random_uuid() produces different values on different nodes of a replicated database like Pgpool-II. Therefore we no longer support the extension pgcrypto.

Version 20

RMB v20+ is based on RAML 1.0. This is a breaking change from RAML 0.8 and there are multiple changes that must be implemented by modules that upgrade to this version.

1. Update the "raml-util" git submodule to use its "raml1.0" branch.
2. MUST change 0.8 to 1.0 in all RAML files (first line)
3. MUST remove the '-' signs from the RAML
   For example:
        CHANGE:  - configs: !include... TO: configs: !include...
4. MUST change the "schemas:" section to "types:"
5. MUST change 'repeat: true' attributes in traits (see our facets) TO type: string[]
6. MUST ensure that documentation field is this format:
     - title: Foo
       content: Bar
7. In resource types change 'schema:' to 'type:'
   This also means that the '- schema:' in the raml is replaced with 'type:'
   For example:
              type: <<schema>>
8. Remove suffixes from key names in the RAML file.
   Any suffix causes a problem (even `.json`) when it is used to populate
   placeholders in the RAML file.
   Declare only types/schemas in RAML that are used in RAML (no need to declare types
   that are only used in JSON schema references).
   For example:
            notify.json: !include notify.json
            notify: !include notify.json
            "notify" is referenced anywhere in the raml
9. JSON schema references may use relative pathname (RMB will dereference them).
   No need to declare them in the RAML file.

10. The resource type examples must not be strict (will result in invalid json content otherwise)
            example: <<exampleItem>>
                strict: false
                value: <<exampleItem>>
11. Generated interfaces do not have the 'Resource' suffix
    For example:
        ConfigurationsResource -> Configurations
12. Names of generated pojos (also referenced by the generated interfaces) may change
    For example:
        kv_configuration: !include ../_schemas/kv_configuration.schema
        will produce a pojo called: KvConfiguration

    Referencing the kv_configuration in a schema (example below will produce a pojo called Config)
    which means the same pojo will be created twice with different names.
    Therefore, it is preferable to synchronize names.
            "configs": {
              "id": "configurationData",
              "type": "array",
              "items": {
                "type": "object",
                "$ref": "kv_configuration"
    This may affect which pojo is referenced by the interface - best to use the same name.
13. Generated methods do not throw exceptions anymore.
    This will require removing the 'throws Exception' from the implementing methods.
14. Names of generated methods has changed
15. The response codes have changed:
        withJsonOK -> respond200WithApplicationJson
        withNoContent -> respond204
        withPlainBadRequest -> respond400WithTextPlain
        withPlainNotFound -> respond404WithTextPlain
        withPlainInternalServerError -> respond500WithTextPlain
        withPlainUnauthorized -> respond401WithTextPlain
        withJsonUnprocessableEntity -> respond422WithApplicationJson
        withAnyOK -> respond200WithAnyAny
        withPlainOK -> respond200WithTextPlain
        withJsonCreated -> respond201WithApplicationJson

    Since RMB v23.3.0 PgUtil provides the methods deleteById, getById, post and put that
    automatically create the correct response.

    Note: For 201 / created codes, the location header has changed and is no longer a string
    but an object and should be passed in as:
      PostConfigurationsEntriesResponse.headersFor201().withLocation(LOCATION_PREFIX + ret)
16. Multipart formdata is currently not supported
17. Remove the declaration of trait "secured" auth.raml and its use from RAML files.
    It has been removed from the shared raml-util.