Automatic Signing and Publishing of Android Apps from Travis

As I discussed about preparing the apps in Play Store for automatic deployment and Google App Signing in previous blogs, in this blog, I’ll talk about how to use Travis Ci to automatically sign and publish the apps using fastlane, as well as how to upload sensitive information like signing keys and publishing JSON to the Open Source repository. This method will be used to publish the following Android Apps: Phimp.me Loklak wok SUSI AI Open Event Orga App PSLab Current Project Structure The example project I have used to set up the process has the following structure: It’s a normal Android Project with some .travis.yml and some additional bash scripts in scripts folder. The update-apk.sh file is standard app build and repo push file found in FOSSASIA projects. The process used to develop it is documented in previous blogs. First, we’ll see how to upload our keys to the repo after encrypting them. Encrypting keys using Travis Travis provides a very nice documentation on encrypting files containing sensitive information, but a crucial information is buried below the page. As you’d normally want to upload two things to the repo - the app signing key, and API JSON file for release manager API of Google Play for Fastlane, you can’t do it separately by using standard file encryption command for travis as it will override the previous encrypted file’s secret. In order to do so, you need to create a tarball of all the files that need to be encrypted and encrypt that tar instead. Along with this, before you need to use the file, you’ll have to decrypt in in the travis build and also uncompress it for use. So, first install Travis CLI tool and login using travis login (You should have right access to the repo and Travis CI in order to encrypt the files for it) Then add the signing key and fastlane json in the scripts folder. Let’s assume the names of the files are key.jks and fastlane.json Then, go to scripts folder and run this command to create a tar of these files: tar cvf secrets.tar fastlane.json key.jks   secrets.tar will be created in the folder. Now, run this command to encrypt the file travis encrypt-file secrets.tar   A new file secrets.tar.enc will be created in the folder. Now delete the original files and secrets tar so they do not get added to the repo by mistake. The output log will show the the command for decryption of the file to be added to the .travis.yml file. Decrypting keys using Travis But if we add it there, the keys will be decrypted for each commit on each branch. We want it to happen only for master branch as we only require publishing from that branch. So, we’ll create a bash script prep-key.sh for the task with following content #!/bin/sh set -e export DEPLOY_BRANCH=${DEPLOY_BRANCH:-master} if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_REPO_SLUG" != "iamareebjamal/android-test-fastlane" -o "$TRAVIS_BRANCH" != "$DEPLOY_BRANCH" ]; then echo "We decrypt key only for…

Continue ReadingAutomatic Signing and Publishing of Android Apps from Travis

Enabling Google App Signing for Android Project

Signing key management of Android Apps is a hectic procedure and can grow out of hand rather quickly for large organizations with several independent projects. We, at FOSSASIA also had to face similar difficulties in management of individual keys by project maintainers and wanted to gather all these Android Projects under singular key management platform: Phimp.me Pocket Science Lab loklak wok Open Event Android and sample apps eventyay Organizer App Ask SUSI.AI To handle the complexities and security aspect of the process, this year Google announced App Signing optional program where Google takes your existing key’s encrypted file and stores it on their servers and asks you to create a new upload key which will be used to sign further updates of the app. It takes the certificates of your new upload key and maps it to the managed private key. Now, whenever there is a new upload of the app, it’s signing certificate is matched with the upload key certificate and after verification, the app is signed by the original private key on the server itself and delivered to the user. The advantage comes where you lose your key, its password or it is compromised. Before App Signing program, if your key got lost, you had to launch your app under a new package name, losing your existing user base. With Google managing your key, if you lose your upload key, then the account owner can request Google to reassign a new upload key as the private key is secure on their servers. There is no difference in the delivered app from the previous one as it is still finally signed by the original private key as it was before, except that Google also optimizes the app by splitting it into multiple APKs according to hardware, demographic and other factors, resulting in a much smaller app! This blog will take you through the steps in how to enable the program for existing and new apps. A bit of a warning though, for security reasons, opting in the program is permanent and once you do it, it is not possible to back out, so think it through before committing. For existing apps: First you need to go to the particular app’s detail section and then into Release Management > App Releases. There you would see the Get Started button for App Signing. The account owner must first agree to its terms and conditions and once it's done, a page like this will be presented with information about app signing infrastructure at top. So, as per the instructions, download the PEPK jar file to encrypt your private key. For this process, you need to have your existing private key and its alias and password. It is fine if you don’t know the key password but store password is needed to generate the encrypted file. Then execute this command in the terminal as written in Step 2 of your Play console: java -jar pepk.jar --keystore={{keystore_path}} --alias={{alias}} --output={{encrypted_file_output_path}} --encryptionkey=eb10fe8f7c7c9df715022017b00c6471f8ba8170b13049a11e6c09ffe3056a104a3bbe4ac5a955f4ba4fe93fc8cef27558a3eb9d2a529a2092761fb833b656cd48b9de6a You will have to…

Continue ReadingEnabling Google App Signing for Android Project

Preparing for Automatic Publishing of Android Apps in Play Store

I spent this week searching through libraries and services which provide a way to publish built apks directly through API so that the repositories for Android apps can trigger publishing automatically after each push on master branch. The projects to be auto-deployed are: Open Event Orga App Open Event Android PSLab Android Loklak Wok Android Phimpe Android SUSI Android I had eyes on fastlane for a couple of months and it came out to be the best solution for the task. The tool not only allows publishing of APK files, but also Play Store listings, screenshots, and changelogs. And that is only a subset of its capabilities bundled in a subservice supply. There is a process before getting started to use this service, which I will go through step by step in this blog. The process is also outlined in the README of the supply project. Enabling API Access The first step in the process is to enable API access in your Play Store Developer account if you haven’t done so. For that, you have to open the Play Dev Console and go to Settings > Developer Account > API access. If this is the first time you are opening it, you’ll be presented with a confirmation dialog detailing about the ramifications of the action and if you agree to do so. Read carefully about the terms and click accept if you agree with them. Once you do, you’ll be presented with a setting panel like this: Creating Service Account As you can see there is no registered service account here and we need to create one. So, click on CREATE SERVICE ACCOUNT button and this dialog will pop up giving you the instructions on how to do so: So, open the highlighted link in the new tab and Google API Console will open up, which will look something like this: Click on Create Service Account and fill in these details: Account Name: Any name you want Role: Project > Service Account Actor And then, select Furnish a new private key and select JSON. Click CREATE. A new JSON key will be created and downloaded on your device. Keep this secret as anyone with access to it can at least change play store listings of your apps if not upload new apps in place of existing ones (as they are protected by signing keys). Granting Access Now return to the Play Console tab (we were there in Figure 2 at the start of Creating Service Account), and click done as you have created the Service Account now. And you should see the created service account listed like this: Now click on grant access, choose Release Manager from Role dropdown, and select these PERMISSIONS: Of course you don’t want the fastlane API to access financial data or manage orders. Other than that it is up to you on what to allow or disallow. Same choice with expiry date as we have left it to never expire. Click on ADD USER and…

Continue ReadingPreparing for Automatic Publishing of Android Apps in Play Store

Adding Static Code Analyzers in Open Event Orga Android App

This week, in Open Event Orga App project (Github Repo), we wanted to add some static code analysers that run on each build to ensure that the app code is free of potential bugs and follows a certain style. Codacy handles a few of these things, but it is quirky and sometimes produces false positives. Furthermore, it is not a required check for builds so errors can creep in gradually. We chose checkstyle, PMD and Findbugs for static analysis as they are most popular for Java. The area they work on kind of overlaps but gives security regarding code quality. Findbugs actually analyses the bytecode instead of source code to find possible JVM bugs. Adding dependencies The first step was to add the required dependencies. We chose the library android-check as it contained all 3 libraries and was focused on Android and easily configurable. First, we add classpath in project level build.gradle dependencies { classpath 'com.noveogroup.android:check:1.2.4' }   Then, we apply the plugin in app level build.gradle apply plugin: 'com.noveogroup.android.check'   This much is enough to get you started, but by default, the build will not fail if any violations are found. To change this behaviour, we add this block in app level build.gradle check { abortOnError true }   There are many configuration options available for the library. Do check out the project github repo using the link provided above Configuration The default configuration is of easy level, and will be enough for most projects, but it is of course configurable. So we took the default hard configs for 3 analysers and disabled properties which we did not need. The place you need to store the config files is the config folder in either root project directory or the app directory. The name of the config file should be checkstyle.xml, pmd.xml and findbugs.xml These are the default settings and you can obviously configure them by following the instructions on the project repo Checkstyle For checkstyle, you can find the easy and hard configuration here The basic principle is that if you need to add a check, you include a module like this: <module name="NewlineAtEndOfFile" />   If you want to modify the default value of some property, you do it like this: <module name="RegexpSingleline"> <property name="format" value="\s+$" /> <property name="minimum" value="0" /> <property name="maximum" value="0" /> <property name="message" value="Line has trailing spaces." /> <property name="severity" value="info" /> </module>   And if you want to remove a check, you can ignore it like this: <module name="EqualsHashCode"> <property name="severity" value="ignore" /> </module>   It’s pretty straightforward and easy to configure. Findbugs For findbugs, you can find the easy and hard configuration here Findbugs configuration exists in the form of filters where we list resources it should skip analyzing, like: <Match> <Class name="~.*\.BuildConfig" /> </Match>   If we want to ignore a particular pattern, we can do so like this: <!-- No need to force hashCode for simple models --> <Match> <Bug pattern="HE_EQUALS_USE_HASHCODE " /> </Match>   Sometimes, you’d want to only…

Continue ReadingAdding Static Code Analyzers in Open Event Orga Android App
Read more about the article Automatic handling of view/data interactions in Open Event Orga App
Abstract 3d white geometric background. White seamless texture with shadow. Simple clean white background texture. 3D Vector interior wall panel pattern.

Automatic handling of view/data interactions in Open Event Orga App

During the development of Open Event Orga Application (Github Repo), we have strived to minimize duplicate code wherever possible and make the wrappers and containers around data and views intelligent and generic. When it comes to loading the data into views, there are several common interactions and behaviours that need to be replicated in each controller (or presenter in case of MVP architecture as used in our project). These interactions involve common ceremony around data loading and setting patterns and should be considered as boilerplate code. Let’s look at some of the common interactions on views: Loading Data While loading data, there are 3 scenarios to be considered: Data loading succeeded - Pass the data to view Data loading failed - Show appropriate error message Show progress bar on starting of the data loading and hide when completed If instead of loading a single object, we load a list of them, then the view may be emptiable, meaning you’ll have to show the empty view if there are no items. Additionally, there may be a success message too, and if we are refreshing the data, there will be a refresh complete message as well. These use cases present in each of the presenter cause a lot of duplication and can be easily handled by using Transformers from RxJava to compose common scenarios on views. Let’s see how we achieved it. Generify the Views The first step in reducing repetition in code is to use Generic classes. And as the views used in Presenters can be any class such as Activity or Fragment, we need to create some interfaces which will be implemented by these classes so that the functionality can be implementation agnostic. We broke these scenarios into common uses and created disjoint interfaces such that there is little to no dependency between each one of these contracts. This ensures that they can be extended to more contracts in future and can be used in any View without the need to break them down further. When designing contracts, we should always try to achieve fundamental blocks of building an API rather than making a big complete contract to be filled by classes. The latter pattern makes it hard for this contract to be generally used in all classes as people will refrain from implementing all its methods for a small functionality and just write their own function for it. If there is a need for a class to make use of a huge contract, we can still break it into components and require their composition using Java Generics, which we have done in our Transformers. First, let’s see our contracts. Remember that the names of these Contracts are opinionated and up to the developer. There is no rule in naming interfaces, although adjectives are preferred as they clearly denote that it is an interface describing a particular behavior and not a concrete class: Emptiable A view which contains a list of items and thus can be empty public interface Emptiable<T>…

Continue ReadingAutomatic handling of view/data interactions in Open Event Orga App

Binding Images Dynamically in Open Event Orga App

In Open Event Orga App (Github Repo), we used Picasso to load images from URLs and display in ImageViews. Picasso is easy to use, lightweight, and extremely configurable but there has been no new release of the library since 2015. We were using Picasso in binding adapters in order to dynamically load images using POJO properties in the layout XML itself using Android Data Binding. But this configuration was a little buggy. The first time the app was opened, Picasso fetched the image but it was not applied to the ImageView. When the device was rotated or the activity was resumed, it loaded just fine. This was a critical issue and we tried many things to fix it but none of it quite fit our needs. We considered moving on to other Image Loading libraries like Glide, etc but it was too heavy on the size and functionality for our needs. The last resort was to update the library to develop version using Sonatype’s snapshots Repository. Now, the Picasso v2.6.0-SNAPSHOT is very stable but not released to the maven central repository, and a newer develop version v3.0.0-SNAPSHOT was launched too. So we figured we should use that. This blog will outline the steps to include the develop version of Picasso, configuring it for our needs and making it work with Android Data Binding. Setting up Dependencies Firstly, we need to include the sonatype repository in the repositories block of our app/build.gradle repositories { ... maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } }   Then we need to replace the Picasso dependency entry to this: compile 'com.squareup.picasso:picasso:3.0.0-SNAPSHOT'   Note that if you used Jake Wharton’s OkHttp3 Downloader for Picasso, you won’t need it now, so you need to remove it from the dependency block And you need to use this to import the downloader import com.squareup.picasso.OkHttp3Downloader;   Next, we set up our Picasso DI this way Picasso providesPicasso(Context context, OkHttpClient client) { Picasso picasso = new Picasso.Builder(context) .downloader(new OkHttp3Downloader(client)) .build(); picasso.setLoggingEnabled(true); return picasso; }   Set the singleton instance in our application: Picasso.setSingletonInstance(picasso);   And we are ready to use it. Creating Adapters Circular Image Adapter We show event logos as circular images, so we needed to create a binding adapter for that: @BindingAdapter("circleImageUrl") public static void bindCircularImage(ImageView imageView, String url) { if(TextUtils.isEmpty(url)) { imageView.setImageResource(R.drawable.ic_photo_shutter); return; } Picasso.with() .load(Uri.parse(url)) .error(R.drawable.ic_photo_shutter) .placeholder(R.drawable.ic_photo_shutter) .transform(new CircleTransform()) .tag(MainActivity.class) .into(imageView); }   If the URL is empty, we just show the default photo, and otherwise we load the image into the view using standard CircleTransform Note that there is no context argument in the with method. This was implemented in Picasso recently where they removed the need for context for loading images. Now, they use a Dummy ContentProvider to get application context, which is inspired by how Firebase does it. Now, we can just normally use this binding in layout to load the event thumbnail like this <ImageView android:layout_width="@dimen/image_small" android:layout_height="@dimen/image_small" android:contentDescription="@string/event_thumbnail" app:circleImageUrl="@{event.thumbnailImageUrl}" />   This gives us a layout like this: Next we need to load the header…

Continue ReadingBinding Images Dynamically in Open Event Orga App

Adding Sentry Integration in Open Event Orga Android App

Sentry is a service that allows you to track events, issues and crashes in your apps and provide deep insights with context about them. This blog post will discuss how we implemented it in Open Event Orga App (Github Repo). Configuration First, we need to include the gradle dependency in build.gradle compile 'io.sentry:sentry-android:1.3.0' Now, our project uses proguard for release builds which obfuscates the code and removes unnecessary class to shrink the app. For the crash events to make sense in Sentry dashboard, we need proguard mappings to be uploaded every time release build is generated. Thankfully, this is automatically handled by sentry through its gradle plugin, so to include it, we add this in our project level build.gradle in dependencies block classpath 'io.sentry:sentry-android-gradle-plugin:1.3.0'   And then apply the plugin by writing this at top of our app/build.gradle apply plugin: 'io.sentry.android.gradle'   And then configure the options for automatic proguard configuration and mappings upload sentry { // Disables or enables the automatic configuration of proguard // for Sentry. This injects a default config for proguard so // you don't need to do it manually. autoProguardConfig true // Enables or disables the automatic upload of mapping files // during a build. If you disable this you'll need to manually // upload the mapping files with sentry-cli when you do a release. autoUpload false }   We have set the autoUpload to false as we wanted Sentry to be an optional dependency to the project. If we turn it on, the build will crash if sentry can’t find the configuration, which we don’t want to happen. Now, as we want Sentry to configurable, we need to set Sentry DSN as one of the configuration options. The easiest way to externalize configuration is to use environment variables. There are other methods to do it given in the official documentation for config https://docs.sentry.io/clients/java/config/ Lastly, for proguard configuration, we also need 3 other config options, namely: defaults.project=your-project defaults.org=your-organisation auth.token=your-auth-token   For getting the auth token, you need to go to https://sentry.io/api/ Now, the configuration is complete and we’ll move to the code Implementation First, we need to initialise the sentry instance for all further actions to be valid. This is to be done when the app starts, so we add it in onCreate method Application class of our project by calling this method // Sentry DSN must be defined as environment variable // https://docs.sentry.io/clients/java/config/#setting-the-dsn-data-source-name Sentry.init(new AndroidSentryClientFactory(getApplicationContext()));   Now, we’re all set to send crash reports and other events to our Sentry server. This would have required a lot of refactoring if we didn’t use Timber for logging. We are using default debug tree for debug build and a custom Timber tree for release builds. if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree()); else Timber.plant(new ReleaseLogTree());   The ReleaseLogTree extends Timber.Tree which is an abstract class requiring you to override this function: @Override protected void log(int priority, String tag, String message, Throwable throwable) { }   This function is called whenever there is a log event through Timber and this…

Continue ReadingAdding Sentry Integration in Open Event Orga Android App

Implementing Attendee Detail BottomSheet UI in Open Event Orga App

In Open Event Orga App (Github Repo), we allow the option to check the attendee details before checking him/her in or out. Originally, a dialog was shown showing the attendee details, which did not contain much information about the attendee, ticket or the order. The disadvantage of such design was also that it was tied to only one view. We couldn’t show the check in dialog elsewhere in the app, like during QR scanning. So we had to switch back to the attendee view for showing the check in dialog. We decided to create a usable detached component in the form of a bottom sheet containing all required information. This blog will outline the procedure we employed to design the bottom sheet UI. The attendee check in dialog looked like this: So, first we decide what we need to show on the check in bottom sheet: Attendee Name Attendee Email Attendee Check In Status Order Status ( Completed, Pending, etc ) TIcket Type ( Free, Paid, Donation ) Ticket Price Order Date Invoice Number Order ‘Paid Via’ As we are using Android Data Binding in our layout, we’ll start by including the variables required in the layout. Besides the obvious attendee variable, we need presenter instance to handle the check in and check out of the attendee and DateUtils class to parse the order date. Additionally, to handle the visibility of views, we need to include the View class too <data> <import type="org.fossasia.openevent.app.utils.DateUtils" /> <import type="android.view.View" /> <variable name="presenter" type="org.fossasia.openevent.app.event.checkin.contract.IAttendeeCheckInPresenter" /> <variable name="checkinAttendee" type="org.fossasia.openevent.app.data.models.Attendee" /> </data>   Then, we make the root layout to be CoordinatorLayout and add a NestedScrollView inside it, which contains a vertical linear layout in it. This vertical linear layout will contain our fields. Note: For brevity, I’ll skip most of the layout attributes from the blog and only show the ones that correspond to the text Firstly, we show the attendee name: <TextView style="@style/TextAppearance.AppCompat.Headline" android:text='@{attendee.firstName + " " + attendee.lastName }' tools:text="Name" />   The perks of using data binding can be seen here, as we are using string concatenation in layout itself. Furthermore, data binding also handles null checks for us if we add a question mark at the end of the variable name ( attendee.firstName? ). But our server ensures that both these fields are not null, so we skip that part. Next up, we display the attendee email <TextView android:text="@{ checkinAttendee.email }" tools:text="xyz@example.com" />   And then the check in status of the attendee <TextView android:text="@{ checkinAttendee.checkedIn ? @string/checked_in : @string/checked_out }" android:textColor="@{ checkinAttendee.checkedIn ? @color/light_green_500 : @color/red_500 }" tools:text="CHECKED IN" />   Notice that we dynamically change the color and text based on the check in status of the attendee Now we begin showing the fields with icons to their left. You can use Compound Drawable to achieve this effect, but we use vector drawables which are incompatible with compound drawables on older versions of Android, so we use a horizontal LinearLayout instead. The first field is the order status denoting…

Continue ReadingImplementing Attendee Detail BottomSheet UI in Open Event Orga App

Invalidating user login using JWT in Open Event Orga App

User authentication is an essential part of Open Event Orga App (Github Repo), which allows an organizer to log in and perform actions on the event he/she organizes. Backend for the application, Open Event Orga Server sends an authentication token on successful login, and all subsequent privileged API requests must include this token. The token is a JWT (Javascript Web Token) which includes certain information about the user, such as identifier and information about from when will the token be valid, when will it expire and a signature to verify if it was tampered. Parsing the Token Our job was to parse the token to find two fields: Identifier of user Expiry time of the token We stored the token in our shared preference file and loaded it from there for any subsequent requests. But, the token expires after 24 hours and we needed our login model to clear it once it has expired and shown the login activity instead. To do this, we needed to parse the JWT and compare the timestamp stored in the exp field with the current timestamp and determine if the token is expired. The first step in the process was to parse the token, which is essentially a Base 64 encoded JSON string with sections separated by periods. The sections are as follows: Header ( Contains information about algorithm used to encode JWT, etc ) Payload ( The data in JWT - exp. Iar, nbf, identity, etc ) Signature ( Verification signature of JWT ) We were interested in payload and for getting the JSON string from the token, we could have used Android’s Base64 class to decode the token, but we wanted to unit test all the util functions and that is why we opted for a custom Base64 class for only decoding our token. So, first we split the token by the period and decoded each part and stored it in a SparseArrayCompat public static SparseArrayCompat<String> decode(String token) { SparseArrayCompat<String> decoded = new SparseArrayCompat<>(2); String[] split = token.split("\\."); decoded.append(0, getJson(split[0])); decoded.append(1, getJson(split[1])); return decoded; }   The getJson function is primarily decoding the Base64 string private static String getJson(String strEncoded) { byte[] decodedBytes = Base64Utils.decode(strEncoded); return new String(decodedBytes); } The decoded information was stored in this way 0={"alg":"HS256","typ":"JWT"}, 1={"nbf":1495745400,"iat":1495745400,"exp":1495745800,"identity":344} Extracting Information Next, we create a function to get the expiry timestamp from the token. We could use GSON or Jackson for the task, but we did not want to map fields into any object. So we simply used JSONObject class which Android provides. It took 5 ms on average to parse the JSON instead of 150 ms by GSON public static long getExpiry(String token) throws JSONException { SparseArrayCompat<String> decoded = decode(token); // We are using JSONObject instead of GSON as it takes about 5 ms instead of 150 ms taken by GSON return Long.parseLong(new JSONObject(decoded.get(1)).get("exp").toString()); }   Next, we wanted to get the ID of user from token to determine if a new user is logging in or an old one, so…

Continue ReadingInvalidating user login using JWT in Open Event Orga App

Shrinking Model Classes Boilerplate in Open Event Android Projects Using Jackson and Lombok

JSON is the de facto standard format used for REST API communication, and for consuming any of such API on Android apps like Open Event Android Client and Organiser App, we need Plain Old Java Objects, or POJOs to map the JSON attributes to class properties. These are called models, for they model the API response or request. Basic structure of these models contain Private properties representing JSON attributes Getters and Setters for these properties used to change the object or access its data A toString() method which converts object state to a string, useful for logging and debugging purposes An equals and hashcode method if we want to compare two objects These can be easily and automatically be generated by any modern IDE, but add unnecessarily to the code base for a relatively simple model class, and are also difficult to maintain. If you add, remove, or rename a method, you have to change its getters/setters, toString and other standard data class methods. There are a couple of ways to handle it: Google’s Auto Value: Creates Immutable class builders and creators, with all standard methods. But, as it generates a new class for the model, you need to add a library to make it work with JSON parsers and Retrofit. Secondly, there is no way to change the object attributes as they are immutable. It is generally a good practice to make your models immutable, but if you are manipulating their data in your application and saving it in your database, it won’t be possible except than to create a copy of that object. Secondly, not all database storage libraries support it Kotlin’s Data Classes: Kotlin has a nice way to made models using data classes, but it has certain limitations too. Only parameters in primary constructor will be included in the data methods generated, and for creating a no argument constructor (required for certain database libraries and annotation processors), you either need to assign default value to each property or call the primary constructor filling in all the default values, which is a boilerplate of its own. Secondly, sometimes 3rd party libraries are needed to work correctly with data classes on some JSON parsing frameworks, and you probably don’t want to just include Kotlin in your project just for data classes Lombok: We’ll be talking about it later in this blog Immutables, Xtend Lang, etc This is one kind of boilerplate, and other kind is JSON property names. As we know Java uses camelcase notation for properties, and JSON attributes are mostly: Snake Cased: property_name Kebab Cased: property-name Whether you are using GSON, Jackson or any other JSON parsing framework, it works great for non ambiguous property names which match as same in both JSON and Java, but requires special naming attributes for translating JSON attributes to camelcase and vice versa. Won’t you want your parser to intelligently convert property_name to propertyName without having you write the tedious mapping which is not only a boilerplate, but also error…

Continue ReadingShrinking Model Classes Boilerplate in Open Event Android Projects Using Jackson and Lombok