Duck typing in standard Java.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
java7
java8
.gitattributes
.gitignore
.travis.yml
CHANGELOG.md
LICENSE
README.md
ROADMAP.md
pom.xml

README.md

Java Quacking

Build Status

This is simple library helping to implement some sort of duck typing. Only standard Java features are used so duck typing is accomplished with dynamic proxys, reflection, and some sort of type checking.

Instead of creating adapters between interfaces, or wrappers for decoration, we can mix instances and override methods without even implementing the interface, which forces us to implement all it's methods (without a default implementation).

For example, in the typical situation where you want your servlets to be able to obtain the character encoding from the request and ensure it's never null, you have to wrap the request, delegate all methods (but getCharacterEnconding()) to a real request, and implement getCharacterEnconding() to perform what you want.

Fortunately there is the HttpServletRequestWrapper which starts by delegating everything to a real request.

public class ForceCharacterEncodingWrapper extends HttpServletRequestWrapper {

    private String encoding;
    
    public ForceCharacterEncodingWrapper(HttpServletRequest request, String encoding) {
        super(request);
        this.encoding = encoding;
    }
    
    @Override
    public String getCharacterEncoding() {
        return this.encoding;
    }
    
}

And then, somewhere, you would wrap the real request and pass it on.

HttpServletRequest wrappedRequest = new ForceCharacterEncodingWrapper(getRequest(), "UTF-8");
Assert.assertEquals("UTF-8", wrappedRequest.getCharacterEncoding());

By using this form of mixins you can use a more liberal pattern. The object you implement only has the method you want to override and does not even need to implement the request's interface.

public class ForceCharacterEncoding {
	
	private String encoding;
	
	public ForceCharacterEncoding(String encoding) {
		this.encoding = encoding;
	}

	public String getCharacterEncoding() {
		return this.encoding;
	}
	
}

Then you can mix this object in front of a real request. The resulting mixing can be used as a HttpServletRequest and forwarded to the servlet.

Mixin mixin = Mixins.create(new ForceCharacterEncoding("UTF-8"), getRequest());
HttpServletRequest mixedRequest = mixin.as(HttpServletRequest.class);
Assert.assertEquals("UTF-8", mixedRequest.getCharacterEncoding());

Note that ForceCharacterEncoding has no dependency on the Servlet API. Also, the same object could be mixed in front of a HttpServletResponse because the method has the same name. If the method has a different name, web could still mix it by renaming an interface method to the object's getCharacterEncoding.

Mixin mixin = new Mixin();
mixin.mix(new ForceCharacterEncoding("UTF-8")).rename("toString", "getCharacterEncoding");
mixin.mix(getRequest());

HttpServletRequest mixedRequest = mixin.as(HttpServletRequest.class);
Assert.assertEquals("UTF-8", mixedRequest.toString());

These are trivial examples but the main idea is that you can avoid dependencies and use mixing as a more reusable way to adapt and extend frameworks that don't quite work together but have all the required methods just different interfaces, names, arguments, etc.

License

The library is under The MIT License. You can check LICENSE for the full license.