• This repository has been archived on 26/Aug/2021
  • Stars
    star
    351
  • Rank 116,746 (Top 3 %)
  • Language
    Java
  • License
    MIT License
  • Created almost 8 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Speedy Type Adapter Generation

⚠️⚠️⚠️ This library has been deprecated and will be removed in the future. ⚠️⚠️⚠️

Stag

Stag improves Gson performance by automatically generating reflection-less TypeAdapters for your model objects.

Build Status codecov Download

Why Build Stag?

Gson is the essential JSON parsing library. It greatly simplifies what can be the verbose and boilerplate-ridden process of parsing JSON into model objects. It does this by leveraging reflection. Unfortunately, using reflection can be slow (particularly on the Android OS).

You can work around this by writing a custom TypeAdapter, a class that Gson uses to (de)serialize an object. The main use case for custom type adapters is for classes that you don't have control over (e.g. parsing a JSON string into a java.util.Date object). They are used to manually map JSON to fields in your model object. So, you can just write a custom TypeAdapter to tell Gson how to map data to fields and the performance will improve, since it won't have to use reflection.

But... if you have a lot of model objects, and you want to remove the use of reflection for (de)serialization of each one, suddenly you have to write many, many TypeAdapters. If you've ever written one or many of these type adapters, you will know that it is a tedious process. In fact, when writing your own TypeAdapter, you might ask what you are doing using Gson in the first place!!!

The Stag library solves this problem. It leverages annotations to automatically generate reflection-less TypeAdapters for your model objects at compile time. Instead of spending time writing your own custom TypeAdapters for each model object, or forgoing the performance gain of eliminating reflection, use Stag and apply the @UseStag to your model class declarations and all the work will be done for you.

Gradle Usages

1. Add the Stag dependencies

All jar dependencies are available on jcenter.

Java Gradle

buildscript {
    repositories {
        maven { url 'https://plugins.gradle.org/m2/' }
    }
    dependencies {
        classpath 'net.ltgt.gradle:gradle-apt-plugin:0.11'
    }
}

apply plugin: 'net.ltgt.apt'

dependencies {
    def stagVersion = '2.6.0'
    compile "com.vimeo.stag:stag-library:$stagVersion"
    apt "com.vimeo.stag:stag-library-compiler:$stagVersion"
}

// Optional annotation processor arguments (see below)
gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
        aptOptions.processorArgs = [
                "stagAssumeHungarianNotation": "true",
                "stagGeneratedPackageName"   : "com.vimeo.sample.stag.generated",
                "stagDebug "                 : "true",
                "stag.serializeNulls"        : "true",
        ]
    }
}

Kotlin Gradle

apply plugin: 'kotlin-kapt'

dependencies {
    def stagVersion = '2.6.0'
    compile "com.vimeo.stag:stag-library:$stagVersion"
    kapt "com.vimeo.stag:stag-library-compiler:$stagVersion"
}

kapt {
    correctErrorTypes = true
    // Optional annotation processor arguments (see below)
    arguments {
        arg("stagDebug", "true")
        arg("stagGeneratedPackageName", "com.vimeo.sample.stag.generated")
        arg("stagAssumeHungarianNotation", "true")
        arg("stag.serializeNulls", "true")
    }
}

Android Gradle (Java)

dependencies {
    def stagVersion = '2.6.0'
    compile "com.vimeo.stag:stag-library:$stagVersion"
    annotationProcessor "com.vimeo.stag:stag-library-compiler:$stagVersion"
}

android {
    ...
    defaultConfig {
        ...
        // Optional annotation processor arguments (see below)
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [
                    "stagAssumeHungarianNotation": 'true',
                    "stagGeneratedPackageName"   : 'com.vimeo.sample.stag.generated',
                    "stagDebug"                  : 'true',
                    "stag.serializeNulls"        : 'true'
                ]
            }
        }
    }
}

2. Provide optional compiler arguments to Stag

  • stagGeneratedPackageName: Pass package name as an argument for the generated files. By default, the files will be in generated in com.vimeo.stag.generated package. You can specify your own package for the generated files by passing it as an argument to the annotation processor.
  • stagDebug: Turn on debugging in Stag. This will cause Stag to spit out a lot of output into the gradle console. This can aid you in figuring out what class is giving you trouble, if the exception gradle prints out isn't sufficient. Default is false.
  • stagAssumeHungarianNotation: If your Java member variables are private and Stag needs to use setters and getters to access the field, Stag will look for members named set[variable_name] and get[variable_name]. If your member variables are named using Hungarian notation, then you will need to pass true to this parameter so that for a field named mField, Stag will look for setField and getField instead of setMField and getMField. Default is false.
  • stag.serializeNulls: By default this is set to false. If an object has a null field and you send it to be serialized by Gson, it is optional whether or not that field is serialized into the JSON. If this field is set to false null fields will not be serialized, and if set to true, they will be serialized. Prior to stag version 2.6.0, null fields were always serialized to JSON. This should not affect most models. However, if you have a model that has a nullable field that also has a non null default value, then it might be a good idea to turn this option on.

Features

1. Class Level Annotation

Stag supports class level annotation @UseStag which processes all the fields for a particular class, which makes it easy to use and integrate.

@UseStag has three different variants:

  • @UseStag(FieldOption.ALL): Will serialize/de-serialize all member variables which are not static or transient
  • @UseStag(FieldOption.NONE): Will skip serialization and deserialization for all member variables. Only member variables inherited from annotated classes will be included.
  • @UseStag(FieldOption.SERIALIZED_NAME): Will Serialize or Deserialize Fields only which are annotated with SerializedName.

2. @SerializedName("key") Support

Similar to GSON, you can use the@SerializedName annotation to provide a different JSON name to a member field. It also supports alternate name feature of the @SerializedName annotation. @SerializedName("name") or @SerializedName(value = "name", alternate = {"name1", "name2"}).

3. Cross Module Support

Stag has the ability to reference TypeAdapters across modules.

4. Parity with GSON

Last but not the least, Stag is almost in parity with GSON.

Stag Rules

  1. Make sure that any private member variables have setters/getters following these naming rules:
    private String myString;
    
    public String getMyString() { ... }
    
    public void setMyString(String parameter) { ... }
    Java setters and getters must have protected, public, or package local visibility. If you don't want to use setters and getters, make sure your member variables have protected, public, or package local visibility. If working with Kotlin, currently, you must make sure your getters all have public visibility. Because stag generates Java code, the only way it knows how to access the Kotlin fields is if the setters and getters are public. By default, the visibility set on a Kotlin member variable is also applied to its setters and getters.
  2. Make sure your model class is not private and has a zero argument non-private constructor
  3. Annotate the classes with @UseStag annotation. This will process all the member variables of the class, which makes it easy to use.
  4. Use the @SerializedName("key") annotation to give the variables a different JSON name. (same as GSON)
  5. Use your favorite @NonNull annotation to tell Stag to throw an exception if the field is null while deserializing or while serializing the object.
  6. Register the Stag.Factory with Gson when you create your Gson instance: Gson gson = new GsonBuilder().registerTypeAdapterFactory(new Stag.Factory()).create();
  7. Make sure that you are not reusing the Stag.Factory instance between Gson instances. The factory is stateful and must be recreated when creating a new Gson instance. If you try to reuse the instance, an UnsupportedOperationException will be thrown.
  8. You're done!
  9. [Optional] By default, stag will drop a file called StagTypeAdapterFactory.list into your build folder which contains the plaintext names of all your models. It is used by the compiler to generate the adapters. It's a very small file and will compress down to a few bytes in size, but if you don't want it in your compiled apk, you can exclude it using the following code (if you supply a custom package name as a compiler argument, use that in place of com/vimeo/stag/generated/ below):
packagingOptions {
    exclude 'com/vimeo/stag/generated/StagTypeAdapterFactory.list'
}

See the example below or the sample app to get more info on how to use Stag.

Example

Java

@UseStag
public class Deer {

    // Private fields require getters and setters
    @SerializedName("name")
    private String name;    // name = json value with key "name"
    
    @SerializedName("species")
    String species; // species = json value with key "species"
    
    @SerializedName("age")
    int age;        // age = json value with key "age"
    
    @SerializedName("points")
    int points;     // points = json value with key "points"
    
    @SerializedName("weight")
    float weight;   // weight = json value with key "weight"
    
    public String getName() { return name; }
    
    public void setName(String name) { this.name = name; }
}

@UseStag
public class Herd {

    @NonNull                     // add NonNull annotation to throw an exception if the field is null
    @SerializedName("data_list")
    ArrayList<Deer> data;        // data = json value with key "data_list"
    
    List<Deer> data_list_copy;   // data_list_copy = json value with key "data_list_copy"
    
    Map<String, Deer> data_map;  // data_map = json value with key "data_map"
}

Kotlin

@UseStag
class Deer {

    @SerializedName("name")
    var name: String? = null    // name = json value with key "name"

    @SerializedName("species")
    var species: String? = null // species = json value with key "species"

    @SerializedName("age")
    var age: Int = 0        // age = json value with key "age"

    @SerializedName("points")
    var points: Int = 0     // points = json value with key "points"

    @SerializedName("weight")
    var weight: Float = 0.toFloat()   // weight = json value with key "weight"
}

@UseStag
class Herd {

    // non null fields will be honored buy throwing an exception if the field is null
    @SerializedName("data_list")
    var data: ArrayList<Deer> = ArrayList()     // data = json value with key "data_list"

    var data_list_copy: List<Deer>? = null   // data_list_copy = json value with key "data_list_copy"

    var data_map: Map<String, Deer>? = null  // data_map = json value with key "data_map"
}

Consuming Model in Java

/**
 * The class where you receive JSON 
 * containing a list of Deer objects.
 * You parse the list from JSON using
 * Gson.
 */
class MyParsingClass {
    private Gson gson = new GsonBuilder()
                                 .registerTypeAdapterFactory(new Stag.Factory())
                                 .create();

    public Herd fromJson(String json) {
        return gson.fromJson(json, Herd.class);
    }
}

Future Enhancements

  • Add an option to absorb parsing errors rather than crashing and halting parsing (default gson behavior)
  • Support internal visibility in Kotlin code
  • Generate Kotlin code for Kotlin models

Development

git clone [email protected]:vimeo/stag-java.git
cd stag-java
bundle install
# dev like a boss
bundle exec fastlane test
# commit and push like a boss

Manage build dependencies

Aside from specifying Java dependencies in the .gradle files, you can use the .travis.yml file to specify external build depencies such as the Android SDK to compile against (see the android.components section).

License

stag-java is available under the MIT license. See the LICENSE file for more information.

Questions

Post on Stack Overflow with the tag vimeo-android.

More Repositories

1

psalm

A static analysis tool for finding errors in PHP applications
PHP
5,440
star
2

player.js

Interact with and control an embedded Vimeo Player.
JavaScript
1,413
star
3

graph-explorer

A graphite dashboard powered by structured metrics
Python
1,060
star
4

php-mysql-engine

A MySQL engine written in pure PHP
PHP
544
star
5

player-api

Examples for our JavaScript and ActionScript player APIs.
450
star
6

vimeo.php

Official PHP library for the Vimeo API.
PHP
445
star
7

laravel

A Vimeo bridge for Laravel
PHP
384
star
8

VIMVideoPlayer

Deprecated: Please use [PlayerKit]( https://github.com/vimeo/PlayerKit) instead.
Objective-C
281
star
9

vimeo.js

Official Node.js library for the Vimeo API.
JavaScript
264
star
10

vimeo-oembed-examples

Some examples of how to use our oEmbed endpoint
HTML
237
star
11

vimeo.py

Official Python library for the Vimeo API.
Python
210
star
12

vimeo-unity-sdk

Easily stream your Vimeo videos into Unity or record and publish out to Vimeo.
C#
208
star
13

graphite-influxdb

An influxdb backend for Graphite-web and graphite-api
Python
198
star
14

vimeo-php-lib

Our official PHP library for the Advanced API.
PHP
180
star
15

tailgate

Tailgate is a nodejs app to pipe `tail -F` into websockets. It's a very simple way to have real-time access to your logs.
JavaScript
164
star
16

ABLincoln

A library for online experiments.
PHP
154
star
17

PlayerKit

Swift
154
star
18

vimeo-networking-java

The Vimeo Java (Android) SDK
Kotlin
122
star
19

py-money

Money class for Python 3
Python
121
star
20

vimeo-threejs-player

A plugin for streaming video from Vimeo to WebGL/VR/AR apps
JavaScript
88
star
21

tattletale.js

A utility to send console logs over XHR for server-side processing.
JavaScript
87
star
22

VimeoNetworking

The Vimeo API iOS SDK
Swift
83
star
23

vimeo-depth-player

A WebVR volumetric video renderer that uses color-depth based videos hosted on Vimeo.
JavaScript
83
star
24

aframe-vimeo-component

Stream Vimeo videos into WebVR.
JavaScript
81
star
25

simple-black-box

A simple black-box behavior testing framework
Shell
68
star
26

pentagon

Vault <-> Kubernetes Secrets
Go
59
star
27

VimeoUpload

The Vimeo iOS Upload SDK
Swift
59
star
28

whisper-to-influxdb

migrate (import) graphite data from whisper to influxdb
Go
58
star
29

smoketcp

Smokeping like tcp connectivity tester, reports to statsd. written in Golang
Go
58
star
30

VIMNetworking

The Vimeo iOS SDK
Objective-C
58
star
31

libvmod-boltsort

A fast Varnish module for sorting query string parameters.
C
58
star
32

vimeo-depth-viewer

OpenGL application for viewing depth and color video streams from Intel RealSense cameras
C++
52
star
33

iris

Vimeo Design System
TypeScript
50
star
34

carbon-tagger

native tag-based metrics for graphite/carbon
Go
50
star
35

go-util

Small reusable Go functions.
Go
44
star
36

Blueprint

aka How We Collaborate
41
star
37

graphite-api-influxdb-docker

docker image with graphite-api and graphite-influxdb
Shell
39
star
38

go-magic

Go Bindings for libmagic and an idiomatic API for getting a file's MIME type.
Go
39
star
39

rollup-plugin-bundle-size

A rollup plugin to show the size of the generated bundle(s).
JavaScript
29
star
40

vimeo-maxmsp

Play and manipulate Vimeo videos in Max/MSP and Jitter
Max
24
star
41

openapi

An OpenAPI specification for the Vimeo API.
17
star
42

VIMDeeplink

Simple Objc and Swift wrappers around the Vimeo iOS deeplink API
Swift
17
star
43

puppet-diamond

diamond module for puppet
Puppet
15
star
44

nagios-cloudwatch-plugin

AWS CloudWatch check Nagios plugin
Python
14
star
45

elevator

Validate and patch AV1 levels
Rust
12
star
46

puppet-statsd

statsd module for puppet
Puppet
11
star
47

VIMUpload

This library has been deprecated, use VimeoUpload instead
Objective-C
11
star
48

go-hammer

Go
10
star
49

VIMObjectMapper

An automatic JSON to model object converter
Objective-C
10
star
50

babel-plugin-transform-i18n

A Babel transform plugin to replace strings with their translations.
JavaScript
10
star
51

dials

Dials is an extensible configuration package for Go.
Go
9
star
52

go-clocks

A convenient package providing a Clock abstraction in Go
Go
9
star
53

go-taglog

Based on, and compatible with, the Go standard log package, but also provides additional functionality and features such as tagging.
Go
8
star
54

leaderelection

Go
8
star
55

ios-labs-staffpicks

An iOS Labs sample project
Swift
7
star
56

zendesk-ticket-history

JavaScript
7
star
57

grouplogger

Go
6
star
58

netstorage

go client for the new Akamai Netstorage http api
Go
6
star
59

caps

Go package to read/write popular video caption formats(mostly a port of pycaption)
Go
6
star
60

Uniform

Swift
6
star
61

alog

Another Go Logging Package
Go
5
star
62

vimeo-live-player-examples

Example application for using Vimeo Live M3U8 links with third-party players
HTML
5
star
63

graph-explorer-docker

Shell
5
star
64

eslint-config-player

ESLint config for all player team projects.
JavaScript
5
star
65

go-iccjpeg

A small utility package to extract ICC profiles from JPEGs.
Go
4
star
66

graphite-go

Go
4
star
67

go-retry

A small package for doing comprehensive retries.
Go
4
star
68

go-imgparse

A small go library to efficiently parse the resolution of various image format streams.
Go
4
star
69

vimeo-deeplink-android

A helper library to deep link into the official Vimeo Android App
Java
3
star
70

payment-gateway-logger

PHP
3
star
71

av1stats

An AV1 stream analysis CLI tool
Rust
3
star
72

omnipay-bluesnap

BlueSnap driver for the Omnipay PHP payment processing library
PHP
3
star
73

genepool

A golang package for building generic workpools in a standardized way
Go
2
star
74

omnipay-vindicia

Vindicia driver for the Omnipay PHP payment processing library
PHP
2
star
75

VimeoCommon

1
star
76

k8swatcher

Convenient watching interface for Kubernetes.
Go
1
star
77

policy

1
star