org.xpertss:proximo

Proximo provides a simple declarative means for creating proxies and stubbing method behavior overrides.

License

License

GroupId

GroupId

org.xpertss
ArtifactId

ArtifactId

proximo
Last Version

Last Version

1.0
Release Date

Release Date

Type

Type

jar
Description

Description

org.xpertss:proximo
Proximo provides a simple declarative means for creating proxies and stubbing method behavior overrides.
Project URL

Project URL

https://github.com/cfloersch/Proximo
Source Code Management

Source Code Management

https://github.com/cfloersch/Proximo

Download proximo

How to add to project

<!-- https://jarcasting.com/artifacts/org.xpertss/proximo/ -->
<dependency>
    <groupId>org.xpertss</groupId>
    <artifactId>proximo</artifactId>
    <version>1.0</version>
</dependency>
// https://jarcasting.com/artifacts/org.xpertss/proximo/
implementation 'org.xpertss:proximo:1.0'
// https://jarcasting.com/artifacts/org.xpertss/proximo/
implementation ("org.xpertss:proximo:1.0")
'org.xpertss:proximo:jar:1.0'
<dependency org="org.xpertss" name="proximo" rev="1.0">
  <artifact name="proximo" type="jar" />
</dependency>
@Grapes(
@Grab(group='org.xpertss', module='proximo', version='1.0')
)
libraryDependencies += "org.xpertss" % "proximo" % "1.0"
[org.xpertss/proximo "1.0"]

Dependencies

test (2)

Group / Artifact Type Version
junit : junit jar 4.6
org.mockito : mockito-all jar 1.8.2

Project Modules

There are no modules declared in this project.

Proximo

Proximo is a rip off of the mockito mocking system but applied to java.lang.reflect.Proxy instances. It provides a simple declarative means for creating proxies and stubbing method behavior overrides.

Example 1:

  HttpServletRequest proxy = Proximo.proxy(HttpServletRequest.class, request);
  doReturn("joeshmoe").when(proxy).getRemoteUser();
  filterChain.doFilter(proxy, response);

The above example overrides the getRemoteUser() method from HttpServletRequest to return a specific user name. This would be useful for implementing a ServletFilter which authenticates a user and wishes to propagate the username through the standard interface method.

Example 2:

  Iterator<String> keys = myCacheMap.keys().iterator();
  Iterator<String> proxy = Proximo.proxy(Iterator.class, keys);
  doThrow(new UnsupportedOperationException()).when(proxy).remove();

The above is an example of a simple immutable Iterator wrapper that prevents cache keys from being removed via the iterator.

Example 3:

  List<String> proxy = Proximo.proxy(List.class, myList);
  doNothing().when(proxy).clear();

The above example proxies a List implementation and ensures that calls to clear are ignored.

Example 4:

  Map<String,String> cache = Proximo.proxy(Map.class, myBackingMap);
  doAnswer(new Answer() {
    public void answer(Invocation invocation) throws Throwable {
      String key = invocation.getArgumentAt(0, String.class).toUpperCase();
      String value = invocation.getArgumentAt(1, String.class);
      return invocation.getMethod().invoke(invocation.getProxied(), new Object[] { key, value });
   }
  }).when(cache).put(anyString(),anyString());

The above example wraps Map instance and forces all of the key's to be upper case using a custom behavior.

Argument Matchers

Argument matchers allow specific method calls (with arguments) to be overridden.

Example:

  List<String> list = Proximo.proxy(List.class, myBackingList);
  doReturn("john?").when(list).get(eq(0));

In the above example the proxied instance's get method will NOT be called if and only if the supplied index is 0. In that case "john?" will be returned. Use a different index value and the actual list will be queried.

Example 2:

   public interface Joiner {
      public String join(char c, Object... objects);
   }
   Joiner proxy = Proximo.proxy(Joiner.class, myJoinerImpl);
   doReturn("Ha Ha").when(proxy).join(anyChar(), anyVarargs());

The above example we return "Ha Ha" for any call made to the vararg method join irrespective to the type or number of variable arguments.

Example 3:

   public interface Joiner {
      public String join(char c, Object... objects);
   }
   Joiner proxy = Proximo.proxy(Joiner.class, myJoinerImpl);
   doNothing().when(proxy).join(anyChar(), eq("chris"), anyString());

   // prints nothing
   System.out.println(proxy.join(' ', "chris", "singer"));

   // prints chris 1973
   System.out.println(proxy.join(' ', "chris", 1973));

   // prints chris john frank
   System.out.println(proxy.join(' ', "chris", "john", "frank"));

In the above example we override the join method if any only if there are exactly two string arguments (varargs) passed to the join method. The first one equaling "chris" and the second one being of any string value. The first call matches the specified argument matchers. The second call does not match because the second vararg is an Integer rather than a string. The third call does not match because there are three strings supplied rather than the stubbed requirement of two.

Precedence

When a stubbed method is executed a matching answer is found using a precedence from most specific to least specific. That means matchers that are more specific will be evaluated before those that are less specific.

Example:

  List<String> proxy = Proximo.proxy(List.class, myList);
  doReturn("no").when(proxy).get(eq(3));
  doReturn("yes").when(proxy).get(anyInt());

In the above example the stubbing which returns "no" is more specific than the stubbing that returns "yes" and as such will be evaluated first for a match. If the supplied argument is three it will of course match and be executed. For all other values we fall through to the more generic stubbing which accepts any integer value.

Example 2:

   public interface Joiner {
      public String join(char c, Object... objects);
   }
   Joiner proxy = Proximo.proxy(Joiner.class, myJoinerImpl);
   doReturn("yes").when(proxy).join(anyChar(), eq("fred"));
   doReturn("no").when(proxy).join(eq(' '), anyString());

   // prints "no"
   System.out.println(proxy.join(' ', "fred");

In the above example it is ambiguous which is more specific as they both have a single highly specific matcher and a secondary generic matcher. In this case the one stubbed last will be evaluated first. It will in effect override the first stubbing in all cases where the separator char is a space.

Chaining

In the rare event that you wish subsequent calls to behave differently you may use chaining to accomplish that goal.

Example:

   List<String> items = Proximo.proxy(List.class, myList);
   doNothing()
     .doForwardCall()
     .when(items)
     .clear();

In the above example the first call to clear will do nothing. All subsequent calls to clear will actually forward the call to the proxied list instance resulting in its content's being cleared.

The important thing to note is that the last DO operation will be executed on all subsequent calls after the initial set of DO operations have been executed.

Versions

Version
1.0