Play!> & JSon : How-to select fields to expose (ExclusionStrategy)

Using JSON as data language to build an API for your Play application, the default behaviour is to render all fields of a class, and this recursively. This means render the fields of a

Here a sample model example that could occurs in a bank application :

A client is specified with this model, that includes the password of the client.

@Entity
public class Client extends Model {
    public String firstname;
    public String lastname;
    public  String password;
    
    public String toString() {
    	return firstname + " " + lastname;
    }
}

This client has accounts in the bank, so a simple model would be :

@Entity
public class Account extends Model {
	@ManyToOne
	public Client owner;
    public String number;
    public Double balance;
    public String label;
    
    public String toString() {
    	return number;
    }
}

One of the first service of the application when a client connects to the application is to show the list of his accounts :

The route is :

GET 	/api/accounts							Operations.listAccounts

And the code of the controller is :

public class Operations extends Controller {
	public static void listAccounts() {
	    List<Account> accounts = Account.find("order by number").fetch();
	    renderJSON(accounts);
	}

}

This code will expose the following json datas :

[{"owner":{"firstname":"xxx","lastname":"xxx","password":"yyyy","id":1},"number":"001","balance":999.99,"label":"ACCOUNT X","id":1},...]

Oh, the password is visible.

So what we will do is to extend Play! with a new Controller class that will use add a Strategy to gson :

package ext;

import play.mvc.Controller;
import play.mvc.Util;
import play.mvc.results.RenderJson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;


public abstract class NoExposeStrategyController extends Controller {
    private static final Gson gson;

    static {

	    gson = new GsonBuilder()
        .addSerializationExclusionStrategy(new NoExposeExclusionStrategy())  
        .create();

    }

    @Util 
    public static void renderJSON(Object object) {
        throw new RenderJson(gson.toJson(object));
    }
}

Now, we will wrtie this strategy. The goal is to exclude fiels annoted (we will use the tag @NoExpose) in the json output.

package ext;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class NoExposeExclusionStrategy implements ExclusionStrategy {

	@Retention(RetentionPolicy.RUNTIME)
	@Target({ ElementType.FIELD })
	public @interface NoExpose {
		// Field tag only annotation
	}

	public NoExposeExclusionStrategy() {
	}

	public boolean shouldSkipClass(Class<?> clazz) {
		return (false);
	}

	public boolean shouldSkipField(FieldAttributes f) {
		return f.getAnnotation(NoExpose.class) != null;
	}

}

You can notice that with exclude fields, but that we can also exclude Classes. This can also be very interesting to exclude a model (so all datas of a particular table).

The main code is done. All we have to do now is just two basic actions.
– change the declaration of our controller(s) :

public class Operations extends NoExposeStrategyController {

-annotate the fields we want to exclude :

    @NoExpose 	
    public  String password;
Advertisements

About this entry