Skip to content

Commit e85d500

Browse files
committed
Moved method lookup to the constructor in WebService
1 parent e3f9a9c commit e85d500

File tree

1 file changed

+116
-120
lines changed

1 file changed

+116
-120
lines changed

src/javaxt/express/WebService.java

Lines changed: 116 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
public abstract class WebService {
2929

3030
private ConcurrentHashMap<String, DomainClass> classes = new ConcurrentHashMap<>();
31-
31+
private LinkedHashMap<String, ArrayList<Method>> serviceMethods = new LinkedHashMap<>();
32+
private boolean strictLookup = false;
3233

3334
public static Console console = new Console(); //do not replace with static import!
3435

@@ -48,6 +49,66 @@ public String toString(){
4849
}
4950

5051

52+
//**************************************************************************
53+
//** Constructor
54+
//**************************************************************************
55+
public WebService(){
56+
57+
//Generate a list of all the service methods in the subclass. Service
58+
//methods are public methods that accept a ServiceRequest parameter and
59+
//return a ServiceResponse object. Implementation note:
60+
//The getDeclaredMethod() method will only find methods declared in the
61+
//current Class, not inherited from supertypes. So we may need to
62+
//traverse up the concrete class hierarchy if this becomes a requirement.
63+
for (Method m : this.getClass().getDeclaredMethods()){
64+
if (Modifier.isPrivate(m.getModifiers())) continue;
65+
66+
if (m.getReturnType().equals(ServiceResponse.class)){
67+
68+
Class<?>[] params = m.getParameterTypes();
69+
if (params.length>0){
70+
if (ServiceRequest.class.isAssignableFrom(params[0])){
71+
String key = m.getName();
72+
if (!strictLookup) key = key.toLowerCase();
73+
ArrayList<Method> methods = serviceMethods.get(key);
74+
if (methods==null){
75+
methods = new ArrayList<>();
76+
serviceMethods.put(key, methods);
77+
}
78+
methods.add(m);
79+
}
80+
}
81+
}
82+
}
83+
84+
85+
86+
//Experimental special case for anonymous classes
87+
if (this.getClass().isAnonymousClass()){
88+
for (Method m : this.getClass().getMethods()){
89+
if (Modifier.isPrivate(m.getModifiers())) continue;
90+
91+
if (m.getReturnType().equals(ServiceResponse.class)){
92+
93+
Class<?>[] params = m.getParameterTypes();
94+
if (params.length>0){
95+
if (ServiceRequest.class.isAssignableFrom(params[0])){
96+
String key = m.getName();
97+
if (!strictLookup) key = key.toLowerCase();
98+
ArrayList<Method> methods = serviceMethods.get(key);
99+
if (methods==null){
100+
methods = new ArrayList<>();
101+
serviceMethods.put(key, methods);
102+
methods.add(m);
103+
}
104+
}
105+
}
106+
}
107+
}
108+
}
109+
}
110+
111+
51112
//**************************************************************************
52113
//** addModel
53114
//**************************************************************************
@@ -132,145 +193,80 @@ public ServiceResponse getServiceResponse(ServiceRequest request, Database datab
132193
String methodName = request.getMethod();
133194

134195

135-
//Find a concrete implementation of the requested method in the subclass
136-
{
137-
138-
boolean strictLookup = false;
139-
if (!strictLookup) methodName = methodName.toLowerCase();
140-
141-
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-
153-
if (m.getReturnType().equals(ServiceResponse.class)){
154-
155-
Class<?>[] params = m.getParameterTypes();
156-
if (params.length>0){
157-
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-
}
170196

197+
//Find a concrete implementation of the requested method in the subclass
198+
if (!strictLookup) methodName = methodName.toLowerCase();
199+
ArrayList<Method> methods = null;
200+
if (serviceMethods.containsKey(methodName)){
201+
methods = serviceMethods.get(methodName);
202+
}
203+
else{
204+
int i = 0;
205+
if (methodName.startsWith("get")) i = 4;
206+
if (methodName.startsWith("save")) i = 5;
207+
if (methodName.startsWith("delete")) i = 6;
171208

209+
if (i>0){
172210

173-
//Experimental special case for anonymous classes
174-
if (this.getClass().isAnonymousClass()){
175-
for (Method m : this.getClass().getMethods()){
176-
if (Modifier.isPrivate(m.getModifiers())) continue;
211+
//Check for a simple method like search() or update() without a
212+
//"get" or "save" or "delete" prefix
213+
methodName = methodName.substring(i-1, i).toLowerCase() + methodName.substring(i);
214+
methods = serviceMethods.get(methodName);
177215

178-
if (m.getReturnType().equals(ServiceResponse.class)){
179216

180-
Class<?>[] params = m.getParameterTypes();
181-
if (params.length>0){
182-
if (ServiceRequest.class.isAssignableFrom(params[0])){
183-
String key = m.getName();
184-
if (!strictLookup) key = key.toLowerCase();
185-
ArrayList<Method> methods = serviceMethods.get(key);
186-
if (methods==null){
187-
methods = new ArrayList<>();
188-
serviceMethods.put(key, methods);
189-
methods.add(m);
190-
}
191-
//methods.add(m);
192-
}
193-
}
194-
}
217+
//Special case for POST requests (e.g. "POST /companies") that
218+
//map to a "save" method (e.g. saveCompanies) that does not exist.
219+
//Let's check if there's a suitable "get" method instead (e.g. getCompanies).
220+
if (methods==null && i==5){ // && methodName.endsWith("s")
221+
methods = serviceMethods.get("get" + methodName);
195222
}
196-
}
197-
198223

199-
200-
//Find service methods that implement the requested method
201-
ArrayList<Method> methods = null;
202-
if (serviceMethods.containsKey(methodName)){
203-
methods = serviceMethods.get(methodName);
204224
}
205-
else{
206-
int i = 0;
207-
if (methodName.startsWith("get")) i = 4;
208-
if (methodName.startsWith("save")) i = 5;
209-
if (methodName.startsWith("delete")) i = 6;
225+
}
210226

211-
if (i>0){
212227

213-
//Check for a simple method like search() or update() without
214-
//a "get" or "save" or "delete" prefix
215-
methodName = methodName.substring(i-1, i).toLowerCase() + methodName.substring(i);
216-
methods = serviceMethods.get(methodName);
228+
//Return ServiceResponse
229+
if (methods!=null){
230+
for (Method m : methods){
231+
Class<?>[] params = m.getParameterTypes();
217232

218233

219-
//Special case for POST requests (e.g. "POST /companies")
220-
//that map to a "save" method (e.g. saveCompanies) that does
221-
//not exist. Let's check if there's a suitable "get" method
222-
//instead (e.g. getCompanies).
223-
if (methods==null && i==5){ // && methodName.endsWith("s")
224-
methods = serviceMethods.get("get" + methodName);
234+
//Check whether the method accepts a ServiceRequest
235+
//or ServiceRequest + Database as inputs
236+
Object[] inputs = null;
237+
if (params.length==1){
238+
inputs = new Object[]{request};
239+
}
240+
else if (params.length==2){
241+
if (Database.class.isAssignableFrom(params[1])){
242+
inputs = new Object[]{request, database};
225243
}
226-
227244
}
228-
}
229245

246+
if (inputs!=null){
230247

231-
//Return ServiceResponse
232-
if (methods!=null){
233-
for (Method m : methods){
234-
Class<?>[] params = m.getParameterTypes();
235248

236-
237-
//Check whether the method accepts a ServiceRequest
238-
//or ServiceRequest + Database as inputs
239-
Object[] inputs = null;
240-
if (params.length==1){
241-
inputs = new Object[]{request};
242-
}
243-
else if (params.length==2){
244-
if (Database.class.isAssignableFrom(params[1])){
245-
inputs = new Object[]{request, database};
246-
}
249+
//Ensure that we don't want to invoke this function!
250+
//For example, the caller might want to call
251+
//super.getServiceResponse(request, database);
252+
//If so, we would end up in a recursion causing a stack
253+
//overflow. Instead of calling getServiceResponse()
254+
//let's just flow down to the CRUD handlers below.
255+
StackTraceElement[] stackTrace = new Exception().getStackTrace();
256+
StackTraceElement el = stackTrace[1];
257+
if (m.getName().equals(el.getMethodName())){
258+
break;
247259
}
248260

249-
if (inputs!=null){
250-
251-
252-
//Ensure that we don't want to invoke this function!
253-
//For example, the caller might want to call
254-
//super.getServiceResponse(request, database);
255-
//If so, we would end up in a recursion causing a
256-
//stack overflow. Instead of calling getServiceResponse()
257-
//let's just flow down to the CRUD handlers below.
258-
StackTraceElement[] stackTrace = new Exception().getStackTrace();
259-
StackTraceElement el = stackTrace[1];
260-
if (m.getName().equals(el.getMethodName())){
261-
break;
262-
}
263-
264261

265-
//If we're still here, call the requested method
266-
//and return the response
267-
try{
268-
m.setAccessible(true);
269-
return (ServiceResponse) m.invoke(this, inputs);
270-
}
271-
catch(Exception e){
272-
return getServiceResponse(e);
273-
}
262+
//If we're still here, call the requested method and return
263+
//the response
264+
try{
265+
m.setAccessible(true);
266+
return (ServiceResponse) m.invoke(this, inputs);
267+
}
268+
catch(Exception e){
269+
return getServiceResponse(e);
274270
}
275271
}
276272
}

0 commit comments

Comments
 (0)