My colleague made an interesting command that AOP is like a drug and once you have tasted it you can spot cross cutting concerns and the mere presence of duplicate code tells you the signs of martin's fowler's bad smell in code.
We use jersey to implement rest apis and our rest apis can be called from Session or BasicAuth or Oauth, after a user is successfully authenticated we inject the caller user object in request as an attribute so the rest api can derive it to further make api level business validation. But that means every api method has to write this ugly piece of code where we inject request into the signature and then add this one line of code to get the user object.
public Response getDevicesForCustomer(@Context HttpServletRequest request, ....) {
User user = (User) request.getAttribute("user");
...
}
This sounds like a perfect cross cutting concern to be baked into AOP layer. What would be nice if we could do it like this
public Response getDevicesForCustomer(@Context User user ....) {
...
}
so it seems its pretty easy to do this in jersey, all you need is to implement a provider and one fellow programmer's blog gave me the ideas that we can even make it with generic templates so I broke the class into two.
public abstract class AbstractRequestAttributeInjectableProvider<E> implements
InjectableProvider<Context, Type>, Injectable<E> {
private final Type t;
protected @Context HttpServletRequest request;
public AbstractRequestAttributeInjectableProvider(Type t) {
this.t = t;
}
@Override
public Injectable<E> getInjectable(ComponentContext ic, Context a, Type c) {
if (c.equals(t)) {
return this;
}
return null;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
}
and then our final User injector
@Provider
public class UserProvider extends AbstractRequestAttributeInjectableProvider<User> {
public UserProvider() {
super(User.class);
}
@Override
public User getValue() {
return (User) request.getAttribute("user");
}
}
Tada lots of boilerplate code is gone.
We use jersey to implement rest apis and our rest apis can be called from Session or BasicAuth or Oauth, after a user is successfully authenticated we inject the caller user object in request as an attribute so the rest api can derive it to further make api level business validation. But that means every api method has to write this ugly piece of code where we inject request into the signature and then add this one line of code to get the user object.
public Response getDevicesForCustomer(@Context HttpServletRequest request, ....) {
User user = (User) request.getAttribute("user");
...
}
This sounds like a perfect cross cutting concern to be baked into AOP layer. What would be nice if we could do it like this
public Response getDevicesForCustomer(@Context User user ....) {
...
}
so it seems its pretty easy to do this in jersey, all you need is to implement a provider and one fellow programmer's blog gave me the ideas that we can even make it with generic templates so I broke the class into two.
public abstract class AbstractRequestAttributeInjectableProvider<E> implements
InjectableProvider<Context, Type>, Injectable<E> {
private final Type t;
protected @Context HttpServletRequest request;
public AbstractRequestAttributeInjectableProvider(Type t) {
this.t = t;
}
@Override
public Injectable<E> getInjectable(ComponentContext ic, Context a, Type c) {
if (c.equals(t)) {
return this;
}
return null;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
}
and then our final User injector
@Provider
public class UserProvider extends AbstractRequestAttributeInjectableProvider<User> {
public UserProvider() {
super(User.class);
}
@Override
public User getValue() {
return (User) request.getAttribute("user");
}
}
Tada lots of boilerplate code is gone.
Comments
Post a Comment