Skip to content

Commit 48d5a43

Browse files
committed
+ Moving spring reflection utilities to runtime so that it can be used by
the invocation helper. + Documentation updates for 0.6 release and annotations. + Guava library updated to 18.0
1 parent 3579314 commit 48d5a43

7 files changed

Lines changed: 192 additions & 31 deletions

File tree

Documentation.java

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
* this later)
3232
*/
3333

34+
import unquietcode.tools.flapi.annotations.Between;
35+
import unquietcode.tools.flapi.annotations.Last;
36+
3437
EmailGenerator.compose(new EmailHelperImpl())
3538
.sender("HAL9000@gmail.com")
3639
.addRecipient("dave@unquietcode.com")
@@ -48,6 +51,9 @@
4851
* new Descriptor using `Flapi.builder()`...`.build()`, making sure to call
4952
* all of the required methods in between. After the call to build you will
5053
* have a descriptor which is ready to be generated.
54+
*
55+
* There are two ways to create a descriptor, via the fluent builder
56+
* or by using [annotations]().
5157
*/
5258

5359
Descriptor builder = Flapi.builder()
@@ -59,7 +65,10 @@
5965
.addMethod("addRecipient(String emailAddress)").atLeast(1)
6066
.addMethod("sender(String emailAddress)").exactly(1)
6167
.addMethod("body(String text)").atMost(1)
62-
.addMethod("send()").last(EmailMessage.class)
68+
.addMethod("send()").last(EmailMessage.import java.lang.Class;
69+
import java.lang.String;
70+
71+
class)
6372
.build();
6473

6574
builder.writeToStream(System.out);
@@ -76,7 +85,7 @@
7685

7786
// Start building a new Descriptor. Zero or more `ExecutionListener`
7887
// instances can be provided. (check out `MethodLogger`, which is
79-
// quite helpful when debugging an error)
88+
// helpful when debugging an error)
8089
Descriptor descriptor = Flapi.builder(ExecutionListener...listeners)
8190

8291
// Set the package for all generated classes. (**required**)
@@ -458,6 +467,61 @@ public enum TestEnum {
458467
.markAsDeprecated(String reason)
459468

460469

470+
/**
471+
* ## Annotations
472+
*
473+
* Yes, you can!
474+
*/
475+
476+
477+
// marks the method as occurring any number of times
478+
@Any
479+
480+
// marks the method as occurring any tim
481+
// copy these from the stuff above
482+
@Any(int group)
483+
484+
//
485+
@AtLeast(int value)
486+
void x()
487+
488+
@AtMost(int value)
489+
490+
@AtMost(int value, int group)
491+
492+
@Between(int minin, int maxInc)
493+
494+
@Exactly(int value)
495+
496+
497+
498+
// marks the method as last
499+
@Last
500+
501+
// last with return value
502+
503+
@After(int group)
504+
505+
506+
// mark a method parameter as a container for another block
507+
// helper. The chain is constructed by looking at the last parameters
508+
// marked with the chain info. In the current implementation, the
509+
// parameters **must** be placed as the last parameters to the method.
510+
//
511+
// The types must match the generic signature of the `AtomicReference` object,
512+
// or else an error will be thrown at runtime.
513+
@BlockChain(Class<?>[] types)
514+
515+
// provide documentation for the method
516+
@Documented(String[] value)
517+
518+
// create a new descriptor by introspecting the class,
519+
// first for Flapi annotations, and then as a generic bean
520+
Descriptor descriptor = Flapi.create(Class class)
521+
522+
523+
524+
461525
/**
462526
* ## Thanks!
463527
* Visit the project [on GitHub](https://github.com/UnquietCode/Flapi)

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Flapi - A fluent API generator for Java
2-
## v0.5.2 [![Build Status](https://travis-ci.org/UnquietCode/Flapi.png?branch=master)](https://travis-ci.org/UnquietCode/Flapi)
2+
## v0.6 [![Build Status](https://travis-ci.org/UnquietCode/Flapi.png?branch=master)](https://travis-ci.org/UnquietCode/Flapi)
33

44
### What is it?
55
Flapi is a code generation library for creating fluent API's in Java.
@@ -22,6 +22,10 @@ Descriptor builder = Flapi.builder()
2222
.addMethod("send()").last(EmailMessage.class)
2323
.build();
2424
```
25+
##### ...or this:
26+
```java
27+
annotation example
28+
```
2529

2630
##### ...into this:
2731
```java

VERSION.md

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
# Version 0.6
2+
Flapi Version 0.6 includes a major update to support annotation based configuration
3+
of descriptors.
4+
5+
### Annotations
6+
You can now create descriptors from annotated helper classes and interfaces. See the documentation section on [annotations]() for more details.
7+
8+
## Resolved Issues
9+
Issues are now handled through GitHub, and historical issues have been migrated from JIRA.
10+
11+
### Features and Improvement
12+
+ [FLAPI-188 / #11]: Support for creating descriptors from annotated helper interfaces.
13+
+ [FLAPI-155 / #52]: Support referencing the current block.
14+
+ [FLAPI-185 / #38]: Add @see to generated documentation pointing to actual Helper methods.
15+
+ [FLAPI-147 / #36]: Provide Wrapper interface for all blocks.
16+
17+
### Bugs
18+
+ [FLAPI-165 / #35]: Get build project working in the reactor build.
19+
20+
### Tasks
21+
+ [FLAPI-190 / #34]: Update docs and wiki with annotations info.
22+
+ [FLAPI-189 / #17]: Move issues from JIRA to GitHub
23+
24+
The full list of tasks and issues included in the release is available on the project's
25+
[Issue Tracker](https://github.com/UnquietCode/Flapi/milestones/0.6).
26+
27+
------------------------------------------------
28+
129
# Version 0.5
230
Flapi Version 0.5 has been released! Here are the highlights.
331

@@ -37,7 +65,8 @@ Previously, the wrapper interface was called `$`. Flapi 0.5 has removed all uses
3765
+ [FLAPI-173] - Document method grouping / triggering in wiki.
3866
+ [FLAPI-182] - Create a mailing list / user group for Flapi.
3967

40-
The full list of tasks and issues included in the release is available on the project's [JIRA](https://unquietcode.atlassian.net/secure/ReleaseNote.jspa?projectId=10160&version=10740).
68+
The full list of tasks and issues included in the release is available on the project's
69+
[Issue Tracker](https://github.com/UnquietCode/Flapi/issues?q=milestone%3A0.5+milestone%3A0.5.1).
4170

4271
------------------------------------------------
4372

@@ -134,7 +163,7 @@ A brand new documentation page is available at
134163
+ [FLAPI-139] - Create two-column documentation of Flapi features.
135164

136165
The full list of tasks and issues included in the release is available on the project's
137-
[JIRA](https://unquietcode.atlassian.net/secure/ReleaseNote.jspa?projectId=10160&version=10640).
166+
[Issue Tracker](https://github.com/UnquietCode/Flapi/issues?q=milestone%3A0.4).
138167

139168
------------------------------------------------
140169

@@ -184,7 +213,7 @@ A screencast which attempts to explain the basic use of Flapi has been posted [h
184213
* [FLAPI-123] - Add PipedProcess example to project.
185214

186215
The full list of tasks and issues included in the release is available on the project's
187-
[JIRA](https://unquietcode.atlassian.net/secure/ReleaseNote.jspa?version=10142&styleName=Text&projectId=10160).
216+
[Issue Tracker](https://github.com/UnquietCode/Flapi/issues?q=milestone%3A0.3).
188217

189218
------------------------------------------------
190219

@@ -209,10 +238,17 @@ This version includes a few notable changes:
209238
+ [FLAPI-25] - Create a test harness to test known cases of compilation failures.
210239
+ [FLAPI-56] - Incorporate existing examples into tests.
211240

241+
242+
The full list of tasks and issues included in the release is available on the project's
243+
[Issue Tracker](https://github.com/UnquietCode/Flapi/issues?q=milestone%3A0.2).
244+
212245
------------------------------------------------
213246

214247
# Version 0.1
215248
Notes also available at: https://github.com/UnquietCode/Flapi/wiki/v0_1
216249
JIRA: https://unquietcode.atlassian.net/secure/ReleaseNote.jspa?projectId=10160&version=10140
217250

218251
Initial beta release.
252+
253+
The full list of tasks and issues included in the release is available on the project's
254+
[Issue Tracker](https://github.com/UnquietCode/Flapi/issues?q=milestone%3A0.1).

flapi-runtime/src/main/java/unquietcode/tools/flapi/runtime/BlockInvocationHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ private Object invokeAndReturn(Method method, Object[] originalArgs, Object prox
101101
Method helperMethod;
102102

103103
// find the helper method
104-
try {
105-
helperMethod = helper.getClass().getMethod(method.getName(), newTypes);
106-
} catch (NoSuchMethodException ex) {
107-
throw new IllegalStateException("internal error", ex);
104+
helperMethod = SpringMethodUtils.findMethod(helper.getClass(), method.getName(), newTypes);
105+
106+
if (helperMethod == null) {
107+
throw new IllegalStateException("unable to locate method '"+method.getName()+"' on helper");
108108
}
109109

110110
// make accessible if not (debatable as to whether this is a good idea)

src/main/java/unquietcode/tools/flapi/SpringMethodUtils.java renamed to flapi-runtime/src/main/java/unquietcode/tools/flapi/runtime/SpringMethodUtils.java

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
/*
2-
* Copyright 2002-2014 the original author or authors.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
16-
package unquietcode.tools.flapi;
1+
/*********************************************************************
2+
Copyright 2014 the Flapi authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
********************************************************************/
16+
package unquietcode.tools.flapi.runtime;
1717

18+
import java.lang.ref.Reference;
19+
import java.lang.ref.SoftReference;
1820
import java.lang.reflect.Method;
19-
import java.util.ArrayList;
20-
import java.util.Arrays;
21-
import java.util.List;
21+
import java.util.*;
2222

2323
/**
2424
* Method reflection methods copied from Spring Framework's ReflectionUtils class,
@@ -27,6 +27,59 @@
2727
public class SpringMethodUtils {
2828

2929

30+
/**
31+
* Attempt to find a {@link java.lang.reflect.Method} on the supplied class with the supplied name
32+
* and parameter types. Searches all superclasses up to {@code Object}.
33+
* <p>Returns {@code null} if no {@link java.lang.reflect.Method} can be found.
34+
* @param clazz the class to introspect
35+
* @param name the name of the method
36+
* @param paramTypes the parameter types of the method
37+
* (may be {@code null} to indicate any signature)
38+
* @return the Method object, or {@code null} if none found
39+
*/
40+
public static Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
41+
Objects.requireNonNull(clazz, "Class must not be null");
42+
Objects.requireNonNull(name, "Method name must not be null");
43+
44+
Class<?> searchType = clazz;
45+
while (searchType != null) {
46+
Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType));
47+
for (Method method : methods) {
48+
if (name.equals(method.getName()) &&
49+
(paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {
50+
return method;
51+
}
52+
}
53+
searchType = searchType.getSuperclass();
54+
}
55+
return null;
56+
}
57+
58+
59+
/**
60+
* Cache for {@link Class#getDeclaredMethods()}, allowing for fast resolution.
61+
*/
62+
private static final Map<Class<?>, Reference<Method[]>> declaredMethodsCache = new WeakHashMap<Class<?>, Reference<Method[]>>();
63+
64+
65+
66+
/**
67+
* This method retrieves {@link Class#getDeclaredMethods()} from a local cache
68+
* in order to avoid the JVM's SecurityManager check and defensive array copying.
69+
*/
70+
private static Method[] getDeclaredMethods(Class<?> clazz) {
71+
Reference<Method[]> ref = declaredMethodsCache.get(clazz);
72+
Method[] result = null;
73+
if (ref != null) { result = ref.get(); }
74+
75+
if (result == null) {
76+
result = clazz.getDeclaredMethods();
77+
declaredMethodsCache.put(clazz, new SoftReference<Method[]>(result));
78+
}
79+
return result;
80+
}
81+
82+
3083
/**
3184
* Perform the given callback operation on all matching methods of the given
3285
* class and superclasses.
@@ -136,4 +189,7 @@ public interface MethodFilter {
136189
*/
137190
boolean matches(Method method);
138191
}
192+
193+
194+
139195
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@
221221
<dependency>
222222
<groupId>com.google.guava</groupId>
223223
<artifactId>guava</artifactId>
224-
<version>14.0.1</version>
224+
<version>18.0</version>
225225
</dependency>
226226

227227
<!-- test dependencies -->

src/main/java/unquietcode/tools/flapi/annotations/AnnotationIntrospector.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
import unquietcode.tools.flapi.Constants;
2222
import unquietcode.tools.flapi.DescriptorBuilderException;
2323
import unquietcode.tools.flapi.IntrospectorSupport;
24-
import unquietcode.tools.flapi.SpringMethodUtils;
2524
import unquietcode.tools.flapi.beans.BeanIntrospector;
2625
import unquietcode.tools.flapi.helpers.AnnotationsHelperImpl;
2726
import unquietcode.tools.flapi.helpers.DocumentationHelperImpl;
2827
import unquietcode.tools.flapi.helpers.MethodHelperImpl;
2928
import unquietcode.tools.flapi.outline.BlockOutline;
3029
import unquietcode.tools.flapi.outline.DescriptorOutline;
3130
import unquietcode.tools.flapi.outline.MethodOutline;
31+
import unquietcode.tools.flapi.runtime.SpringMethodUtils;
3232

3333
import java.lang.annotation.Annotation;
3434
import java.lang.reflect.AnnotatedElement;
@@ -247,6 +247,7 @@ private void handleMethod(MethodOutline methodOutline, Method method) {
247247

248248
BlockOutline blockOutline = handleClass(blockChain.value());
249249
methodOutline.getBlockChain().add(blockOutline);
250+
// methodOutline.getChainParameterPositions().add(i);
250251
}
251252

252253
else {

0 commit comments

Comments
 (0)