java - paginated calls on a service method without changing signature of original method -


i have use case need add pagination inputs (viz. page number , page size) existing service calls (that returns list of results) without changing existing signature (because break existing clients). 1 way of achieving set inputs in threadlocal , have implementation read threadlocal , pagination logic. code point of view, like:

try {     paginationkit.setpaginationinput(pagesize, pagenumber); // set threadlocal     list<specialobject> results = specialservice.getspecialobjs(); //results count equal pagesize value } {     paginationkit.clearpaginationinput(); // clear threadlocal } 

from client's point of view, not @ elegant , wanted wrap functionality better syntactic sugar. there 2 approaches had in mind , wanted know if generic enough use case has been solved pattern elsewhere. there many such services , trying put decorator each of services not desirable.

approach 1: mockito style of mockito.when(methodcall).thenreturn(result) kind of sugar. code may like:

specialservice specialservice = paginationdecorator.prepare(specialservice.class); // spy capable of forwarding calls actual instance list<specialobject> results = paginationdecorator.withpagesize(pagesize).onpage(pagenumber).get(specialservice.getspecialobjs()).get(); // get() added clear threadlocal 

i tried borrow code mockito create spy, ongoingstubbing<t> interface quite intertwined in subsequent call chaining/creation code , smelling of should avoid.

approach 2: use java.util.function capture method call , accept 2 additional parameters pagenumber , pagesize play threadlocals. code may like

list<specialobject> results = paginationdecorator.withpaging(specialservice.getspecialobjs(), pagesize, pagenumber); 

paginationdecorator.java:

public static list<t> withpaging(function<u, list<t>> call, int pagesize, int pagenumber) {     try {         paginationkit.setpaginationinput(pagesize, pagenumber); // set threadlocal         return call.apply(); // clearly, missing here!     } {         paginationkit.clearpaginationinput(); // clear threadlocal     } } 

i not able formulate how use call correctly here.

can please tell me :

  • which of these 2 better approach
  • if available recipe elsewhere using different approach
  • suggest ways forward implement approach 1 or 2. #2 seems cleaner me (if works).

feel free critique approach , in advance read!

p.s.: liked iterator recipe in question, primary problem of syntactic sugar still desired.

your second variant not work, because using wrong interface (function expects input argument) , no syntax create function instance, ordinary invocation expression.

you have several choices

  1. use supplier. interface describes function without parameters , returning value.

    public static <t> t withpaging(supplier<t> call, int pagesize, int pagenumber) {     try {         paginationkit.setpaginationinput(pagesize, pagenumber); // set threadlocal         return call.get();     } {         paginationkit.clearpaginationinput(); // clear threadlocal     } } 

    instead of insisting on return list<t>, allow return type raises versatility. includes possibility return list of something.

    then, may use either, method reference

    list<specialobject> results=paginationdecorator.withpaging(                     specialservice::getspecialobjs, pagesize, pagenumber); 

    or lambda expression:

    list<specialobject> results=paginationdecorator.withpaging(                     () -> specialservice.getspecialobjs(), pagesize, pagenumber); 
  2. stay function, allow caller pass required argument

    public static <t,r> r withpaging(     function<t,r> call, t argument, int pagesize, int pagenumber) {      try {         paginationkit.setpaginationinput(pagesize, pagenumber); // set threadlocal         return call.apply(argument);     } {         paginationkit.clearpaginationinput(); // clear threadlocal     } } 

    now, caller has provide function , value. since intended method instance method, receiver instance can treated function argument

    then, function might again specified either, (now unbound) method reference

    list<specialobject> results=paginationdecorator.withpaging(         specialservice::getspecialobjs, specialservice, pagesize, pagenumber); 

    or lambda expression:

    list<specialobject> results=paginationdecorator.withpaging(         ss -> ss.getspecialobjs(), specialservice, pagesize, pagenumber); 
  3. there alternative both, resorting autocloseable , try-with-resource, rather try…finally. define helper class as:

    interface paging extends autocloseable {     void close();     static paging withpaging(int pagesize, int pagenumber) {         paginationkit.setpaginationinput(pagesize, pagenumber);         return ()->paginationkit.clearpaginationinput();     } } 

    and use like

    list<specialobject> results; try(paging pg=paging.withpaging(pagesize, pagenumber)) {     results=specialservice.getspecialobjs(); } 

    the advantage not break code flow regarding intended action, i.e. unlike lambda expressions may modify local variables inside guarded code. recent ides warn if forget put result of withpaging inside proper try(…) statement. further, if exception thrown , 1 occurs inside cleanup (i.e. clearpaginationinput()), unlike finally, secondary exception not mask primary 1 recorded via addsuppressed instead.

    that’s prefer here.


Comments

Popular posts from this blog

sql - VB.NET Operand type clash: date is incompatible with int error -

SVG stroke-linecap doesn't work for circles in Firefox? -

python - TypeError: Scalar value for argument 'color' is not numeric in openCV -