@@ -126,65 +126,109 @@ public ServiceResponse getServiceResponse(ServiceRequest request, Database datab
126126 throws ServletException {
127127
128128
129+ //Get requested method. Note that the ServiceRequest typically prepends a
130+ //keyword to the request path (e.g. get, save, delete) depending on the
131+ //HTTP request method (e.g. GET, POST, PUT, DELETE)
132+ String methodName = request .getMethod ();
129133
130- //Get requested method
131- String method = request .getMethod ().toLowerCase ();
132134
135+ //Find a concrete implementation of the requested method in the subclass
136+ {
133137
138+ boolean strictLookup = false ;
139+ if (!strictLookup ) methodName = methodName .toLowerCase ();
134140
135- //Check if the subclass has implemented the requested method. Note that
136- //the getDeclaredMethod will only find methods declared in the current
137- //Class, not inherited from supertypes. So we may need to traverse up the
138- //concrete class hierarchy if necessary.
139- for (Method m : this .getClass ().getDeclaredMethods ()){
140- if (Modifier .isPrivate (m .getModifiers ())) continue ;
141141
142- if (m .getName ().equalsIgnoreCase (method )){
142+
143+ //Generate a list of all the service methods in the subclass. Service
144+ //methods are public methods that accept a ServiceRequest parameter
145+ //and return a ServiceResponse object. Implementation note: the
146+ //getDeclaredMethod() method will only find methods declared in the
147+ //current Class, not inherited from supertypes. So we may need to
148+ //traverse up the concrete class hierarchy if this becomes a requirement.
149+ LinkedHashMap <String , ArrayList <Method >> serviceMethods = new LinkedHashMap <>();
150+ for (Method m : this .getClass ().getDeclaredMethods ()){
151+ if (Modifier .isPrivate (m .getModifiers ())) continue ;
152+
143153 if (m .getReturnType ().equals (ServiceResponse .class )){
144154
145155 Class <?>[] params = m .getParameterTypes ();
146156 if (params .length >0 ){
147157 if (ServiceRequest .class .isAssignableFrom (params [0 ])){
158+ String key = m .getName ();
159+ if (!strictLookup ) key = key .toLowerCase ();
160+ ArrayList <Method > methods = serviceMethods .get (key );
161+ if (methods ==null ){
162+ methods = new ArrayList <>();
163+ serviceMethods .put (key , methods );
164+ }
165+ methods .add (m );
166+ }
167+ }
168+ }
169+ }
148170
149171
150- //Check whether the method accepts a ServiceRequest
151- //or ServiceRequest + Database as inputs
152- Object [] inputs = null ;
153- if (params .length ==1 ){
154- inputs = new Object []{request };
155- }
156- else if (params .length ==2 ){
157- if (Database .class .isAssignableFrom (params [1 ])){
158- inputs = new Object []{request , database };
159- }
160- }
172+ //Find service methods that implement the requested method
173+ ArrayList <Method > methods = null ;
174+ if (serviceMethods .containsKey (methodName )){
175+ methods = serviceMethods .get (methodName );
176+ }
177+ else {
178+ int i = 0 ;
179+ if (methodName .startsWith ("get" )) i = 4 ;
180+ if (methodName .startsWith ("save" )) i = 5 ;
181+ if (methodName .startsWith ("delete" )) i = 6 ;
182+
183+ if (i >0 ){
184+ methodName = methodName .substring (i -1 , i ).toLowerCase () + methodName .substring (i );
185+ methods = serviceMethods .get (methodName );
186+ }
187+ }
161188
162- if (inputs !=null ){
163189
190+ //Return ServiceResponse
191+ if (methods !=null ){
192+ for (Method m : methods ){
193+ Class <?>[] params = m .getParameterTypes ();
164194
165- //Ensure that we don't want to invoke this function!
166- //For example, the caller might want to call
167- //super.getServiceResponse(request, database);
168- //If so, we would end up in a recursion causing a
169- //stack overflow. Instead of calling getServiceResponse()
170- //let's just flow down to the CRUD handlers below.
171- StackTraceElement [] stackTrace = new Exception ().getStackTrace ();
172- StackTraceElement el = stackTrace [1 ];
173- if (m .getName ().equals (el .getMethodName ())){
174- break ;
175- }
176195
196+ //Check whether the method accepts a ServiceRequest
197+ //or ServiceRequest + Database as inputs
198+ Object [] inputs = null ;
199+ if (params .length ==1 ){
200+ inputs = new Object []{request };
201+ }
202+ else if (params .length ==2 ){
203+ if (Database .class .isAssignableFrom (params [1 ])){
204+ inputs = new Object []{request , database };
205+ }
206+ }
177207
178- //If we're still here, call the requested method
179- //and return the response
180- try {
181- m .setAccessible (true );
182- return (ServiceResponse ) m .invoke (this , inputs );
183- }
184- catch (Exception e ){
185- return getServiceResponse (e );
186- }
187- }
208+ if (inputs !=null ){
209+
210+
211+ //Ensure that we don't want to invoke this function!
212+ //For example, the caller might want to call
213+ //super.getServiceResponse(request, database);
214+ //If so, we would end up in a recursion causing a
215+ //stack overflow. Instead of calling getServiceResponse()
216+ //let's just flow down to the CRUD handlers below.
217+ StackTraceElement [] stackTrace = new Exception ().getStackTrace ();
218+ StackTraceElement el = stackTrace [1 ];
219+ if (m .getName ().equals (el .getMethodName ())){
220+ break ;
221+ }
222+
223+
224+ //If we're still here, call the requested method
225+ //and return the response
226+ try {
227+ m .setAccessible (true );
228+ return (ServiceResponse ) m .invoke (this , inputs );
229+ }
230+ catch (Exception e ){
231+ return getServiceResponse (e );
188232 }
189233 }
190234 }
@@ -194,6 +238,7 @@ else if (params.length==2){
194238
195239 //If we're still here, see if the requested method corresponds to a
196240 //standard CRUD operation.
241+ String method = request .getMethod ().toLowerCase (); //don't use methodName!
197242 if (method .startsWith ("get" )){
198243
199244 //Find and return model
0 commit comments