how to get annotations in java through reflection - java

this is my annotations:
#RequestMapping(method = RequestMethod.POST, value = "/trade/createrequisition")
now i would like to get request method it is POST in this case and the value it is /trade/createrequisition in this case.
How to do this using reflection in java.
Please help me to resolve this.
EDIT:
this is what is my actual method :
#PreAuthorize("isAuthenticated() and hasPermission(#request, 'CREATE_REQUISITION')")
#RequestMapping(method = RequestMethod.POST, value = "/trade/createrequisition")
public #ResponseBody
void createRequisition(#RequestBody CreateRequisitionRO[] request,
#RequestHeader("validateOnly") boolean validateOnly) {
....
}
this is how i tried to get the #RequestiMapping:
package com.hexgen.reflection;
import java.lang.reflect.Method;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.hexgen.api.facade.HexgenWebAPI;
public class WebAPITest {
public static void main(String[] args) {
try {
Class<HexgenWebAPI> clazz = HexgenWebAPI.class;
Method methodAnnotaion = clazz.getMethod("createRequisition");
RequestMapping methodRequestMappingAnnotation = methodAnnotaion.getAnnotation(RequestMapping.class);
RequestMethod[] methods = methodRequestMappingAnnotation.method();
String[] mappingValues = methodRequestMappingAnnotation.value();
for(RequestMethod req : methods){
System.out.println("RequestMethod : " + req);
}
for (String string : mappingValues) {
System.out.println("mappingValues : " + string);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
but i get this exception :
java.lang.NoSuchMethodException: com.hexgen.api.facade.HexgenWebAPI.createRequisition()
at java.lang.Class.getMethod(Class.java:1605)
at com.hexgen.reflection.WebAPITest.main(WebAPITest.java:12)

As you are trying to get the RequestMapping annotation, and it can be placed at a class or a method, see both uses below:
For a class YourClass:
Class<YourClass> clazz = YourClass.class;
RequestMapping clazzRequestMappingAnnotation = clazz.getAnnotation(RequestMapping.class);
RequestMethod[] methods = clazzRequestMappingAnnotation.method();
String[] mappingValues = clazzRequestMappingAnnotation.value();
For a method methodName at a class YourClass:
Class<YourClass> clazz = YourClass.class;
Method method = clazz.getMethod("methodName");
RequestMapping methodRequestMappingAnnotation = method.getAnnotation(RequestMapping.class);
RequestMethod[] methods = methodRequestMappingAnnotation.method();
String[] mappingValues = methodRequestMappingAnnotation.value();

If this annotation is on a class (eg: Test) then
RequestMapping a = Test.class.getAnnotation(RequestMapping.class);
RequestMethod m = a.getMethod();

Related

Concise HAL+JSON and JSON endpoint implementation?

Is it possible to concisely implement a single HAL-JSON & JSON endpoints in Spring Boot 2? The goal is to have:
curl -v http://localhost:8091/books
return this application/hal+json result:
{
"_embedded" : {
"bookList" : [ {
"title" : "The As",
"author" : "ab",
"isbn" : "A"
}, {
"title" : "The Bs",
"author" : "ab",
"isbn" : "B"
}, {
"title" : "The Cs",
"author" : "cd",
"isbn" : "C"
} ]
}
and for this (and/or the HTTP Accept header since this is a REST API):
curl -v http://localhost:8091/books?format=application/json
to return the plain application/json result:
[ {
"title" : "The As",
"author" : "ab",
"isbn" : "A"
}, {
"title" : "The Bs",
"author" : "ab",
"isbn" : "B"
}, {
"title" : "The Cs",
"author" : "cd",
"isbn" : "C"
} ]
with minimal controller code. These endpoints work as expected:
#GetMapping("/asJson")
public Collection<Book> booksAsJson() {
return _books();
}
#GetMapping("/asHalJson")
public CollectionModel<Book> booksAsHalJson() {
return _halJson(_books());
}
#GetMapping
public ResponseEntity<?> booksWithParam(
#RequestParam(name="format", defaultValue="application/hal+json")
String format) {
return _selectedMediaType(_books(), format);
}
#GetMapping("/asDesired")
public ResponseEntity<?> booksAsDesired() {
return _selectedMediaType(_books(), _format());
}
with the following helpers:
private String _format() {
// TODO: something clever here...perhaps Spring's content-negotiation?
return MediaTypes.HAL_JSON_VALUE;
}
private <T> static CollectionModel<T> _halJson(Collection<T> items) {
return CollectionModel.of(items);
}
private <T> static ResponseEntity<?> _selectedMediaType(
Collection<T> items, String format) {
return ResponseEntity.ok(switch(format.toLowerCase()) {
case MediaTypes.HAL_JSON_VALUE -> _halJson(items);
case MediaType.APPLICATION_JSON_VALUE -> items;
default -> throw _unknownFormat(format);
});
}
but the booksWithParam implementation is too messy to duplicate for each endpoint. Is there a way to get to, or close to, something like the booksAsDesired implementation or something similarly concise?
One way you could tell Spring that you want to support plain JSON is by adding a custom converter for such media types. This can be done by overwriting the extendMessageConverters method of WebMvcConfigurer and adding your custom converters there like in the sample below:
import ...PlainJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.web.config.EnableSpringDataWebSuport;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servelt.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
import javax.annotation.Nonnull;
#Configuration
#EnableSpringeDataWebSupport
public class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void extendMessageConverters(#Nonnull final List<HttpMessageConverter<?>> converters) {
converters.add(new PlainJsonHttpMessageConverter());
}
}
The message converter itself is also no rocket-science as can be seen by the PlainJsonHttpMessageConverter sample below:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsr310.JavaTimeModule;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import javax.annotation.Nonnull;
#Component
public class PlainJsonHttpMessageConverter extends AbstractJackson2HttpMessageConverter {
public PlainJsonHttpMessageConverter() {
super(new ObjectMapper(), MediaType.APPLICATION_JSON);
// add support for date and time format conversion to ISO 8601 and others
this.defaultObjectMapper.registerModule(new JavaTimeModule());
// return JSON payload in pretty format
this.defaultObjectMapper.enable(SerializationFeature.INDENT_OUTPUT);
}
#Override
protected boolean supports(#Nonnull final Class<?> clazz) {
return RepresentationModel.class.isAssignableFrom(clazz);
}
}
This should enable plain JSON support besides HAL-JSON without you having to do any further branching or custom media-type specific conversion within your domain logic or service code.
I.e. let's take a simple task as example case. Within a TaskController you might have a code like this
#GetMapping(path = "/{taskId:.+}", produces = {
MediaTypes.HAL_JSON_VALUE,
MediaType.APPLICATION_JSON_VALUE,
MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE
})
public ResponseEntity<?> task(#PathVariable("taskId") String taskId,
#RequestParam(required = false) Map<String, String> queryParams,
HttpServletRequest request) {
if (queryParams == null) {
queryParams = new HashMap<>();
}
Pageable pageable = RequestUtils.getPageableForInput(queryParams);
final String caseId = queryParams.get("caseId");
...
final Query query = buildSearchCriteria(taskId, caseId, ...);
query.with(pageable);
List<Task> matches = mongoTemplate.find(query, Task.class);
if (!matches.isEmpty()) {
final Task task = matches.get(0);
return ResponseEntity.ok()
.eTag(Long.toString(task.getVersion())
.body(TASK_ASSEMBLER.toModel(task));
} else {
if (request.getHeader("Accept").contains(MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.contentType(MediaTypes.HTTP_PROBLEM_DETAILS_JSON)
.body(generateNotFoundProblem(request, taskId));
} else {
final String msg = "No task with ID " + taskId + " found";
throw new ResponseStatusException(HttpStatus.NOT_FOUND, msg);
}
}
}
which simply retrieves an arbitrary task via its unique identifier and returns the representation for it according to the one specified in the Accept HTTP header. The TASK_ASSEMBLER here is just a custom Spring HATEOAS RepresentationModelAssembler<Task, TaskResource> class that converts task objects to task resources by adding links for certain related things.
This can now be easily tested via Spring MVC tests such as
#Test
public void halJson() throws Exception {
given(mongoTemplate.find(any(Query.class), eq(Task.class)))
.willReturn(setupSingleTaskList());
final ResultActions result = mockMvc.perform(
get("/api/tasks/taskId")
.accept(MediaTypes.HAL_JSON_VALUE)
);
result.andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON_VALUE));
// see raw payload received by commenting out below line
// System.err.println(result.andReturn().getResponse().getContentAsString());
verifyHalJson(result);
}
#Test
public void plainJson() throws Exception {
given(mongoTemplate.find(any(Query.class), eq(Task.class)))
.willReturn(setupSingleTaskList());
final ResultActions result = mockMvc.perform(
get("/api/tasks/taskId")
.accept(MediaType.APPLICATION_JSON_VALUE)
);
result.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE));
// see raw payload received by commenting out below line
// System.err.println(result.andReturn().getResponse().getContentAsString());
verifyPlainJson(result);
}
...
private void verifyHalJson(final ResultActions action) throws Exception {
action.andExpect(jsonPath("taskId", is("taskId")))
.andExpect(jsonPath("caseId", is("caseId")))
...
.andExpect(jsonPath("_links.self.href", is(BASE_URI + "/tasks/taskId")))
.andExpect(jsonPath("_links.up.href", is(BASE_URI + "/tasks")));
}
rivate void verifyPlainJson(final ResultActions action) throws Exception {
action.andExpect(jsonPath("taskId", is("taskId")))
.andExpect(jsonPath("caseId", is("caseId")))
...
.andExpect(jsonPath("links[0].rel", is("self")))
.andExpect(jsonPath("links[0].href", is(BASE_URI + "/tasks/taskId")))
.andExpect(jsonPath("links[1].rel", is("up")))
.andExpect(jsonPath("links[1].href", is(BASE_URI + "/tasks")));
}
Note how links are presented here differently depending on which media type you've selected.

How can I get POST data in swagger-ui?

I have configured swagger-ui in my SpringBoot application.
Following is my code
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
openAppUrl("8080/swagger-ui.html");
}
public static void openAppUrl(String port) {
String url = "http://localhost:" + port;
String os = System.getProperty("os.name").toLowerCase();
Runtime rt = Runtime.getRuntime();
try {
if (os.indexOf("win") >= 0) {
rt.exec("rundll32 url.dll,FileProtocolHandler " + url);
} else if (os.indexOf("mac") >= 0) {
try {
rt.exec("open " + url);
} catch (IOException e) {
System.out.println(e);
}
} else if (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0) {
String[] browsers = { "epiphany", "firefox", "mozilla", "konqueror", "netscape", "opera", "links",
"lynx" };
StringBuffer cmd = new StringBuffer();
for (int i = 0; i < browsers.length; i++)
cmd.append((i == 0 ? "" : " || ") + browsers[i] + " \"" + url + "\" ");
rt.exec(new String[] { "sh", "-c", cmd.toString() });
} else {
return;
}
} catch (Exception e) {
return;
}
return;
}
}
My Controller
package com. server.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com. server.spring.domain.User;
import com. server.spring.service.UserService;
#RestController
#RequestMapping(UsersController.ROOT_RESOURCE_PATH)
public class UsersController {
public static final String ROOT_RESOURCE_PATH = "/rest/secure/v1/users";
#Autowired
private UserService userService;
#RequestMapping(value = "/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> getUsers() {
return userService.getAllUsers();
}
#RequestMapping(value = "/create", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public User createUser(#RequestBody User user) {
return userService.saveUser(user);
}
}
Here it shows the Rest API URL, HTTP Method POST, Response JSON Object. But I don't see the POST Data Obj which is expected in the API call. So without this the Front End developers cann't work on the corresponding API.
So i expect to show POST Data JSON object what this REST Api required from Front end application
Is this the correct way or Do i need to modify it to get the expected one?
You are using an old version of Swagger-ui, that looks like 2.x
The latest is a lot easier to understand, Check it out here:
http://petstore.swagger.io/#/pet/addPet
It sounds like you are giving this to other developers (the Front End developers), In that case I strongly suggest you to look for a way to upgrade, the new version has a much better user experience, also the 2.x UI version is no longer supported.
So to answer your question:
How can I get POST data in swagger-ui?
The actual response you can get it with the [try-it-out] button of the swagger-ui.
And the POST Data Obj expected by the API is what you see on the example.
I got model properties to correctly attach to the body by using examples (Techincally, API Model Properties) on the models. However, my experience with this didn't include Spring, I'm sure that the documentation is similar. You'd add #ApiModelProperty annotation to your User class.
public class User {
private String firstName;
private String lastName;
#ApiModelProperty(value = "User's first name.", example = "John")
public String getFirstName(){}
//...setters
#ApiModelProperty(value = "User's last name.", example = "Smith")
public String getLastName(){}
//...setters
// etc
}
This fills the swagger documentation POST/PUT/etc body with your example strings.

Handlebars if method returns null / empty string

I currently use handlebars in java (com.github.jknack.handlebars)
and have a handlebars helper method to get a link (with some logic behind)
{{ getLink data.node}}
which just render the url /subfolder/link.html
In my handlebars template I now only want to print the url (a-tag) when the helper method returns a non empty string (e.g. there is a link available)
I tried it with
{{#if getLink data.node }}
Link-Text
{{/if}}
but no link was rendered
What would be the correct syntax for my if?
Thanks
RCX
Edit:
getLink Helper Method in LinkHelper.class
public CharSequence getLink(JsonObject node, Options options) throws IOException {
String link = fetchLink(node);
if(link != null){
return link;
}
return "";
}
registered via
HandlebarsTemplateEngineImpl.getHandlebars().registerHelpers(new LinkHelper());
Handlebars.java is not well documented and missing couple of unit tests (consider to contribute if this answer helped), for some reason calling nested JsonObject removed at this commit, you can still call nested String, but there is a trick with parentheses.
Full example:
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Template;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Map;
public class HandlebarsJavaTest {
public static void main(String[] args) throws IOException {
Handlebars handlebars = new Handlebars();
Gson gson = new Gson();
handlebars.registerHelper("getLink", (Helper<Map<String, Object>>) (jsonObject, options) -> {
String link = fetchLink(jsonObject);
return link != null ? link : "";
});
String data = "{'data':{'node':'/bla.html', 'node2':'inside node2'}}";
// Pay attention to parentheses !!!
// {{#if (getLink data.node)}} throws ClassCastException, java.lang.String cannot be cast to java.util.Map
String rawTemplate = "{{#if (getLink data)}} Link-Text {{/if}}";
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> map = gson.fromJson(data, type);
Template template = handlebars.compileInline(rawTemplate);
Context context = Context.newBuilder(map).build();
System.out.println(template.apply(context));
}
private static String fetchLink(Map<String, Object> map) {
try {
return map.get("node").toString();
} catch (NullPointerException npe) {
return null;
}
}
}
Output:
Link-Text
If node is just a string ( same output )
public static void main(String[] args) throws IOException {
Handlebars handlebars = new Handlebars();
Gson gson = new Gson();
handlebars.registerHelper("getLink", (Helper<String>) (node, options) -> node != null ? node : "");
String data = "{'data':{'node':'/bla.html', 'node2':'inside node2'}}";
// Pay attention to parentheses !!!
String rawTemplate = "{{#if (getLink data.node)}} Link-Text {{/if}}";
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> map = gson.fromJson(data, type);
Template template = handlebars.compileInline(rawTemplate);
Context context = Context.newBuilder(map).build();
System.out.println(template.apply(context));
}
If you insist node is an object using this.[data] or this.[data.node] will not do the work, working example for the same output:
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class HandlebarsJavaTest {
public static void main(String[] args) throws Exception {
System.out.println(
new Handlebars()
.registerHelper("getLink", (Helper<JsonObject>) (json, options) -> {
try {
// logic here
return json.get("data").getAsJsonObject().get("node").getAsJsonObject().get("link").getAsString();
} catch (NullPointerException npe) {
return null;
}
})
// Pay attention to parentheses !!
.compileInline("{{#if (getLink this) }} Link-Text {{/if}}")
.apply(
Context
.newBuilder(
new Gson()
.fromJson(
"{ 'data': { 'node': { 'link': '/bla.html' }, 'node2': 'inside node2' } }",
JsonObject.class
)
).build()
)
);
}
}
If you have time, consider to contribute to this open source by adding proper documentation or at least unit tests {{#if (method param)}}.
According to the source code
package com.github.jknack.handlebars;
public class IfBlockTest extends AbstractTest {
#Test
public void falsy() throws IOException {
// empty string
shouldCompileTo("{{#if value}}true{{else}}false{{/if}}", $("value", ""), "false");
BTW, the #if built-in helper will return False for empty string, so if getLink will execute return ""; the if condition will not and the text will not be rendered, to assert this you can add {{else}} before the closing if {{/if}} and see that what is rendered.

FeignClient duplicate invoke remote method

i want use invoke a remote method by use feignclient,but the remote method was execute duplicate ,this is my code(i'm not good at english,so fogive me)
#ViewScoped
#ManagedBean
#Named("cdProductTemplateView")
public class CdProductTemplateView extends BaseView {
public void cdPost() {
//cdProTempContext,just a bean
cdProductClient.cdPost(cdProTempContext);
}
}
client:
#FeignClient(value = "service", path = "/cdproduct")
public interface CdProductClient {
#RequestMapping("/cdPost")
CdProduct cdPost(#RequestBody CdProductTemplateContext
cdProTempContext) throws BusinessException, SystemException;
}
controller:
#RequestMapping("/cdproduct")
#RestController
public class CdProductController{
public CdProduct cdPostProduct(CdProductTemplateContext cdProTempContext, String resPath)
throws BusinessException, SystemException {
return cdProductService.cdPostProduct(cdProTempContext, resPath);
}
#RequestMapping("/cdPost")
public CdProduct cdPost(#RequestBody CdProductTemplateContext cdProTempContext, HttpServletRequest request) {
return cdPostProduct(cdProTempContext, resPath);
}
}
serviceImpl:
#Named("cdProductService")
public class CdProductServiceImpl implements CdProductService {
#Override
public CdProduct cdPostProduct(CdProductTemplateContext
cdProTempContext, String resPath) throws BusinessException, SystemException {
//proPkgRequset: a bean ProductPackageRequest
cdProService.submitProductPackage(proPkgRequset);
//this just invoke method(ICDMarketplaceAPIService.submitProductPackage )
}
}
ICDMarketplaceAPIService
#WebService(targetNamespace = "http://www.***.com", name = "IMarketplaceAPIService")
#XmlSeeAlso({ObjectFactory.class})
public interface ICDMarketplaceAPIService {
#WebMethod(operationName = "SubmitProductPackage")
#Action(input = "http://www.***.com/IMarketplaceAPIService/SubmitProductPackage", output = "http://www.***.com/IMarketplaceAPIService/SubmitProductPackageResponse")
#RequestWrapper(localName = "SubmitProductPackage", targetNamespace = "http://www.***.com", className = "SubmitProductPackage")
#ResponseWrapper(localName = "SubmitProductPackageResponse", targetNamespace = "http://www.***.com", className = "SubmitProductPackageResponse")
#WebResult(name = "SubmitProductPackageResult", targetNamespace = "http://www.***.com")
public ProductIntegrationReportMessage submitProductPackage(
#WebParam(name = "headerMessage", targetNamespace = "http://www.***.com")
HeaderMessage headerMessage,
#WebParam(name = "productPackageRequest", targetNamespace = "http://www.***.com")
ProductPackageRequest productPackageRequest
);
}
when client invoke remote method,the remote method(controller.cdPost,it was execute duplicate ),but if i remove method(ICDMarketplaceAPIService.submitProductPackage, or not use it) or invoke other method (like query),it's ok.What causes the situation to happen, can anyone help me?
Just add the following code in application.yml:
ribbon:
# Max number of retries on the same server (excluding the first try)
MaxAutoRetries: 0
# Max number of next servers to retry (excluding the first server)
MaxAutoRetriesNextServer: 0

Java-Spring Reflection brings method which are not present in the class

I try to investigate classes available in a given package. for time being i have hard coded the class name, I get so many methods which are not available in the class when i try to print all the methods and parameter type the method takes
the following is my main class where i investigate the class and its method :
package com.hexgen.reflection;
`// removed imports to post question`
import com.hexgen.tools.HexgenClassUtils;
public class HexgenWebAPITest {
#SuppressWarnings({ "rawtypes", "unchecked", "unused" })
public static void main(String[] args) {
HexgenWebAPITest test = new HexgenWebAPITest();
HexgenClassUtils hexgenClassUtils = new HexgenClassUtils();
String uri="";
String[] mappingValues=null;
HttpClientRequests httpRequest = new HttpClientRequests();
Class parames = CreateRequisitionRO[].class;
Class booleanVal;
booleanVal = Boolean.TYPE;
Class cls;
try {
List classNames = hexgenClassUtils.findMyTypes("com.hexgen.*");
Iterator<Class> it = classNames.iterator();
while(it.hasNext())
{
Class obj = it.next();
System.out.println("Methods available in : "+obj.getName());
System.out.println("===================================");
if(obj.getName().equals("com.hexgen.api.facade.HexgenWebAPI")){
cls = Class.forName(obj.getName());
cls.getClass();
Method[] method = cls.getDeclaredMethods();
int i=1;
for (Method method2 : method) {
System.out.println(+i+":"+method2.getName());
Class[] parameterTypes = method2.getParameterTypes();
for (Class class1 : parameterTypes) {
System.out.println("Parameter Type : "+class1.getName());
}
i++;
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
this is the Utility Class
package com.hexgen.tools;
// removed imports to post the question here
public class HexgenClassUtils {
#SuppressWarnings({ "rawtypes"})
public List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
List<Class> candidates = new ArrayList<Class>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + "**/*.class";
Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (isCandidate(metadataReader)) {
candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
}
}
}
return candidates;
}
public String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
try {
Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
if (!c.isInterface() && c.getAnnotation(Controller.class) != null) {
return true;
}
}
catch(Throwable e){
}
return false;
}
}
and this is the actual class which i am investigating:
package com.hexgen.api.facade;
`// removed imports to post question here`
import com.hexgen.datauploader.ETLServiceProvider;
import com.hexgen.ro.response.UserDetailsResponse;
/**
* Hexagon Global IT Services (ALL RIGHTS RESERVED) Created with IntelliJ IDEA.
* User: mayankk Date: 23/11/12 Time: 10:27 AM To change this template use File
* | Settings | File Templates.
*/
#Controller
#Transactional
public class HexgenWebAPI {
#Resource(name = "facadeDbFuncs")
private DbFuncs dbFuncs;
#Resource(name = "gatekeeper")
private IGateKeeper gateKeeper;
#Resource(name = "userContext")
private UserContext userContext;
#Resource(name = "costCalc")
private FinancialCalculator financialCalculator;
#Resource(name = "ytmCalc")
private YTMCalculator ytmCalc;
#Resource(name = "etlService")
private ETLServiceProvider etlService;
#Resource(name = "biManager")
private IBIManager biManager;
private String tmpFileName;
Logger logger = LoggerFactory.getLogger(HexgenWebAPI.class);
private Pattern c4Pattern;
public HexgenWebAPI() {
String cmdPattern = "([bsBS])[ ]+(\\w+)[ ]+(\\d+)[ ]*#[ ]*(\\d+\\.?\\d*)";
c4Pattern = Pattern.compile(cmdPattern);
}
#RequestMapping(method = RequestMethod.GET, value = "/user/details")
public #ResponseBody
UserDetailsResponse getLoggedinUserDetails() {
HexGenUser details = (HexGenUser) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
populateImplementationDetails(response);
return response;
}
private void populateImplementationDetails(UserDetailsResponse response) {
logger.debug("Finding revision details");
try {
CodeSource codeSource = this.getClass().getProtectionDomain()
.getCodeSource();
if (codeSource != null) {
JarInputStream jarStream = new JarInputStream(codeSource
.getLocation().openStream());
Manifest manifest = jarStream.getManifest();
logger.debug("Manifest not found!");
if (manifest != null) {
}
}
} catch (Throwable e) {
logger.debug(e.getMessage());
}
logger.debug("Could not find revision details, seems like development environment.");
}
#PreAuthorize("isAuthenticated() and hasPermission(#request, 'CREATE_REQUISITION')")
#RequestMapping(method = RequestMethod.POST, value = "/trade/createrequisition")
public #ResponseBody
void createRequisition(#RequestBody CreateRequisitionRO[] request,
#RequestHeader("validateOnly") boolean validateOnly) {
logger.debug("Starting createRequisition()...");
for (int i = 0; i < request.length; i++) {
CreateRequisitionRO requisitionRequest = request[i];
{
logger.debug("Record is for update ? {}", mr.isUpdate());
logger.debug("attrs are {}", mr.getChangedRecord());
}
gateKeeper.route(request);
}
#PreAuthorize("isAuthenticated() and hasPermission(#request, 'CREATE_ORDER')")
#RequestMapping(method = RequestMethod.POST, value = "/trade/createorder")
public #ResponseBody
void createOrder(#RequestBody CreateOrderRO request,
#RequestHeader("validateOnly") boolean validateOnly) {
TradeDtl orderRow = dbFuncs.references.tradeDtl.findByTransId(request
.getTransRef());
d
logger.debug("Starting createOrder()...");
gateKeeper.route(request);
}
#RequestMapping(method = RequestMethod.POST, value = "/trade/confirmorder")
public #ResponseBody
void confirmOrder(#RequestBody ConfirmOrderRO request,
#RequestHeader("validateOnly") boolean validateOnly) {
logger.debug("Starting confirmOrder()...");
gateKeeper.route(request);
}
#RequestMapping(method = RequestMethod.PUT, value = "/trade/review/approve")
public #ResponseBody
void approveReview(#RequestBody ApproveReviewRO request,
#RequestHeader("validateOnly") boolean validateOnly) {
logger.trace("approveReview({},{})", request, validateOnly);
gateKeeper.route(request);
}
#RequestMapping(method = RequestMethod.PUT, value = "/trade/review/reject")
public #ResponseBody
void rejectReview(#RequestBody RejectReviewRO request,
#RequestHeader("validateOnly") boolean validateOnly) {
logger.trace("HexgenWebAPI.rejectReview({},{})", request, validateOnly);
gateKeeper.route(request);
}
#RequestMapping(method = RequestMethod.PUT, value = "/upload/overwrite/approve")
public #ResponseBody
void approveUpload(#RequestBody ApproveReviewRO request,
#RequestHeader("validateOnly") boolean validateOnly) {
logger.trace("approveUpload({},{})", request, validateOnly);
UploadJobMaster uploadJobMaster = dbFuncs.references.uploadJobMaster.findOne(request.getId());
AbstractUploadOverwriteRO uploadAcceptRO = null;
Class<?> loaderRO = null;
try {
String className = etlService.getOverwriteAcceptEventName(uploadJobMaster.getUploadGenericType());
loaderRO = Class.forName(className);
uploadAcceptRO = (AbstractUploadOverwriteRO) loaderRO.newInstance();
uploadAcceptRO.setUploadID(uploadJobMaster.getUploadId());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
gateKeeper.route((IRO) uploadAcceptRO);
}
#RequestMapping(method = RequestMethod.PUT, value = "/upload/overwrite/reject")
public #ResponseBody
void rejectUpload(#RequestBody RejectReviewRO request,
#RequestHeader("validateOnly") boolean validateOnly) {
try {
String className = etlService.getOverwriteRejectEventName(uploadJobMaster.getUploadGenericType());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
gateKeeper.route((IRO) uploadRejectRO);
}
#RequestMapping(method = RequestMethod.POST, value = "/upload/file")
public #ResponseBody
FileUploadResponse upload(#RequestParam("file") MultipartFile file) {
FileUploadResponse fileUploadResponse = new FileUploadResponse();
try {
file.transferTo(tmpFile);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
fileUploadResponse.setStatusMessage("passed");
return fileUploadResponse;
}
#RequestMapping(method = RequestMethod.POST, value = "/upload/form/{uploadType}/{uploadName}")
public #ResponseBody
void uploadForm(#PathVariable String uploadType,
#PathVariable String uploadName) {
FileReceivedForUploadRO requisitionRequest = new FileReceivedForUploadRO(
gateKeeper.route(requisitionRequest);
}
//Reports
#PostFilter("isAuthenticated() and hasPermission(null, 'REPG' + filterObject.groupId)")
#RequestMapping(method = RequestMethod.GET, value = "/reports/groups")
public #ResponseBody
List<ReportsGroups> RetrieveReportGroups() {
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return biManager.getReportGroups();
}
#PostFilter("isAuthenticated() and hasPermission(null, 'REPN' + filterObject.reportId)")
#RequestMapping(method = RequestMethod.GET, value = "/reports/list")
public #ResponseBody
List<ReportNames> RetrieveReports(#RequestParam("groupId") BigDecimal groupId) {
return biManager.getReportNames(groupId);
}
#PreAuthorize("isAuthenticated() and hasPermission(null, 'REPN' + #reportId)")
#RequestMapping(method = RequestMethod.GET, value = "/reports/fields")
public #ResponseBody
List<FilterParameters> RetrieveReportFields(#RequestParam("reportId") BigDecimal reportId) {
ReportGroupMapping report = dbFuncs.references.reportGroupMapping.findOne(reportId);
return biManager.getFilterParameters(report.getReportName());
}
#PreAuthorize("isAuthenticated() and hasPermission(null, 'REPN' + #request.reportId)")
#RequestMapping(method = RequestMethod.POST, value = "/reports/generateurl")
public #ResponseBody
GenerateURLResponse generateURL(#RequestBody GenerateURLRO request) {
ReportGroupMapping report = dbFuncs.references.reportGroupMapping.findOne(request.getReportId());
try {
return new GenerateURLResponse(biManager.generateURL(report.getReportName(), request.getReportParameters()));
} catch(BOValidationException e) {
throw new ValidationException(e.getViolations());
}
}
// TODO throw away code
#RequestMapping(method = RequestMethod.POST, value = "/upload/eodprocess")
public #ResponseBody
void dayChange() {
DayChangeRO dayChangeRO = new DayChangeRO();
gateKeeper.route(dayChangeRO);
}
#RequestMapping(method = RequestMethod.GET, value = "/overview/holdings")
public #ResponseBody
List<HoldingsRO> generateHoldingsReport() {
List<HoldingsQO> holdingsQO = dbFuncs.references.reportsMgrFinders
.getAllHoldings();
holdingsRO.add(new HoldingsRO(holding.getAssetClass(), holding
.getUnRealTcy(), holding.getUnRealPcy()));
}
return holdingsRO;
}
#RequestMapping(method = RequestMethod.GET, value = "/overview/funds")
public #ResponseBody
List<FundOverviewRO> generatePortfolioTrend() {
List<FundOverviewQO> fundOverviewQO = dbFuncs.references.reportsMgrFinders
.getPortfolioMovement();
List<FundOverviewRO> fundOverviewRO = new ArrayList<FundOverviewRO>();
.getLast30Day()));
}
return fundOverviewRO;
}
#RequestMapping(method = RequestMethod.GET, value = "/fund/holdings/{portfolio}")
public #ResponseBody
List<HoldingsRO> generateHoldingsReport(#PathVariable String portfolio) {
List<HoldingsQO> holdingsQO = dbFuncs.references.reportsMgrFinders
.getFundHoldings(portfolio);
List<HoldingsRO> holdingsRO = new ArrayList<HoldingsRO>();
for (HoldingsQO holding : holdingsQO) {
String securityDescription = holding.getSecurityDescription()
.substring(
0,
Math.min(holding.getSecurityDescription().length(),
20));
holdingsRO.add(new HoldingsRO(holding.getAssetClass(), holding
.getAccrIntTcy(), holding.getAodTcy(), holding
.getUnRealTcy(), holding.getUnRealPcy()));
}
return holdingsRO;
}
#RequestMapping(method = RequestMethod.GET, value = "/fund/concentration/{portfolio}")
public #ResponseBody
ConcentrationRO[] getConcentrationForFund(#PathVariable String portfolio) {
List<ConcentrationRO> concentrations = new ArrayList<ConcentrationRO>();
concentrations
.add(generateConcentrationRO(dbFuncs.references.concentrationFinders
.getAssetGroupExposureFor(userContext.getCompany(),
portfolio)));
concentrations
.add(generateConcentrationRO(dbFuncs.references.concentrationFinders
.getAssetClassExposureFor(userContext.getCompany(),
portfolio)));
concentrations
.add(generateConcentrationRO(dbFuncs.references.concentrationFinders
.getIndustryExposureFor(userContext.getCompany(),
portfolio, "IND")));
return concentrations
.toArray(new ConcentrationRO[concentrations.size()]);
}
#RequestMapping(method = RequestMethod.GET, value = "/overview/concentration")
public #ResponseBody
ConcentrationRO[] getConcentrationForFund() {
List<ConcentrationRO> concentrations = new ArrayList<ConcentrationRO>();
concentrations
.add(generateConcentrationRO(dbFuncs.references.concentrationFinders
.getAssetGroupExposureFor(userContext.getCompany())));
concentrations
.add(generateConcentrationRO(dbFuncs.references.concentrationFinders
.getAssetClassExposureFor(userContext.getCompany())));
concentrations
.add(generateConcentrationRO(dbFuncs.references.concentrationFinders
.getIndustryExposureFor(userContext.getCompany(), "IND")));
return concentrations
.toArray(new ConcentrationRO[concentrations.size()]);
}
public ConcentrationRO generateConcentrationRO(
ConcentrationFinders concentrationFinder) {
ConcentrationRO concentrationRO = new ConcentrationRO();
for (ValueQO valueQO : concentrationFinder.getValues()) {
concentrationRO.addValue(valueQO.getName(), valueQO.getActual(),
valueQO.getGuidance());
}
return concentrationRO;
}
#RequestMapping(method = RequestMethod.POST, value = "/c4/execute")
public #ResponseBody
void executeC4Command(#RequestBody C4CommandRO request) {
logger.debug("Received command for execution : " + request.getCmd());
try {
Matcher matcher = c4Pattern.matcher(request.getCmd());
if (matcher.matches()) {
String parsedTransCode = matcher.group(1);
} else {
logger.debug("Invalid C4 command");
throw new RuntimeException();
}
} catch (Throwable e) {
logger.debug("Ooops !! C4 command execution failed - "
+ e.getMessage());
throw new RuntimeException(e);
}
}
// FIXME C4 throw away code
private void createRequisitionThroughC4(String security, String transCode,
BigDecimal price, BigDecimal quantity) {
logger.debug("Starting createRequisition() through C4...");
try {
Security securityRow = dbFuncs.references.security
.findBySecurity(security);
if (securityRow.getIsIntApplic() || securityRow.getIsDiscounted()) {
createRequisition.setYtm(ytmCalc.computeXIRR(security, price,
userContext.getBusinessDate()));
} else {
createRequisition.setYtm(BigDecimal.ZERO);
}
SystemDefault defaults = dbFuncs.references.systemDefault
.findByParamLevelAndCompanyAndDivisionAndPortfolio(
ParamLevel.PF, userContext.getCompany(),
userContext.getDivision(), portfolio);
OutputValuesFromInvestmentsDO response = financialCalculator
.costSettlementCalculator(input);
createRequisition.setTransSrlNo(BigDecimal.ONE);
if (transCode.equals("BUY")) {
createRequisition.setInflowOutflow(InflowOutflow.I);
} else {
createRequisition.setInflowOutflow(InflowOutflow.O);
}
createRequisition.setFundManager(createRequisition.getUserId());
createRequisition.setCustodianN(defaults.getCustodianN());
gateKeeper.route(createRequisition);
} catch (Throwable e) {
logger.debug("Ooops !! C4 command execution failed - "
+ e.getMessage());
throw new RuntimeException(e);
}
}
}
but the folloing is the out put i get where i see many methods are not present in the class :
1:ajc$get$validator
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
2:ajc$set$validator
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : javax.validation.Validator
3:ajc$get$requestToEventTranslator
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
4:ajc$set$requestToEventTranslator
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.p0.translator.RequestToEventTranslator
5:ajc$interMethodDispatch2$com_hexgen_api_facade_HexgenWebAPIValidation$validate
Parameter Type : com.hexgen.ro.IRO
6:handleValidationException
Parameter Type : com.hexgen.api.facade.ValidationException
7:createRequisition
Parameter Type : [Lcom.hexgen.ro.request.CreateRequisitionRO;
Parameter Type : boolean
8:getLoggedinUserDetails
9:populateImplementationDetails
Parameter Type : com.hexgen.ro.response.UserDetailsResponse
10:excelMDM
Parameter Type : com.hexgen.ro.request.MdmFromExcelRO
11:createOrder
Parameter Type : com.hexgen.ro.request.CreateOrderRO
Parameter Type : boolean
12:confirmOrder
Parameter Type : com.hexgen.ro.request.ConfirmOrderRO
Parameter Type : boolean
13:approveReview
Parameter Type : com.hexgen.ro.request.ApproveReviewRO
Parameter Type : boolean
14:rejectReview
Parameter Type : com.hexgen.ro.request.RejectReviewRO
Parameter Type : boolean
15:approveUpload
Parameter Type : com.hexgen.ro.request.ApproveReviewRO
Parameter Type : boolean
16:rejectUpload
Parameter Type : com.hexgen.ro.request.RejectReviewRO
Parameter Type : boolean
17:upload
Parameter Type : org.springframework.web.multipart.MultipartFile
18:uploadForm
Parameter Type : java.lang.String
Parameter Type : java.lang.String
19:RetrieveReportGroups
20:RetrieveReports
Parameter Type : java.math.BigDecimal
21:RetrieveReportFields
Parameter Type : java.math.BigDecimal
22:generateURL
Parameter Type : com.hexgen.ro.request.GenerateURLRO
23:dayChange
24:generateHoldingsReport
25:generateHoldingsReport
Parameter Type : java.lang.String
26:generatePortfolioTrend
27:getConcentrationForFund
Parameter Type : java.lang.String
28:getConcentrationForFund
29:generateConcentrationRO
Parameter Type : com.hexgen.core.orm.finders.repositories.ConcentrationFinders
30:executeC4Command
Parameter Type : com.hexgen.ro.request.C4CommandRO
31:createRequisitionThroughC4
Parameter Type : java.lang.String
Parameter Type : java.lang.String
Parameter Type : java.math.BigDecimal
Parameter Type : java.math.BigDecimal
32:createRequisition_aroundBody0
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : [Lcom.hexgen.ro.request.CreateRequisitionRO;
Parameter Type : boolean
33:createRequisition_aroundBody1$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : [Lcom.hexgen.ro.request.CreateRequisitionRO;
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : [Lcom.hexgen.ro.IRO;
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
34:createOrder_aroundBody2
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.CreateOrderRO
Parameter Type : boolean
35:createOrder_aroundBody3$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.CreateOrderRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : com.hexgen.ro.IRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
36:confirmOrder_aroundBody4
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.ConfirmOrderRO
Parameter Type : boolean
37:confirmOrder_aroundBody5$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.ConfirmOrderRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : com.hexgen.ro.IRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
38:approveReview_aroundBody6
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.ApproveReviewRO
Parameter Type : boolean
39:approveReview_aroundBody7$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.ApproveReviewRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : com.hexgen.ro.IRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
40:rejectReview_aroundBody8
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.RejectReviewRO
Parameter Type : boolean
41:rejectReview_aroundBody9$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.RejectReviewRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : com.hexgen.ro.IRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
42:approveUpload_aroundBody10
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.ApproveReviewRO
Parameter Type : boolean
43:approveUpload_aroundBody11$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.ApproveReviewRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : com.hexgen.ro.IRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
44:rejectUpload_aroundBody12
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.RejectReviewRO
Parameter Type : boolean
45:rejectUpload_aroundBody13$advice
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : com.hexgen.ro.request.RejectReviewRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPIValidation
Parameter Type : com.hexgen.ro.IRO
Parameter Type : boolean
Parameter Type : com.hexgen.api.facade.HexgenWebAPI
Parameter Type : org.aspectj.runtime.internal.AroundClosure
46:ajc$preClinit
Different parts of the Spring frame-work perform instrumentation at run-time to, to augment classes and provide additional functionality. Spring uses three different kinds of instrumentation:
DynamicProxies - this is a feature of J2SE, and allows generating an interface "on-the-fly" by specifying "method handlers" - a method that gets called to handle method invocations. The handler will look at the method signature and arguments to decide what to do. Typically this will involve adding dome functionality before or after calling a the corresponding method on a concrete target class that implements the same interface. (Hence the name 'proxy'). Dynamic Proxies are the default when a class is backed by an interface.
Byte-code-engineering (BCEL). This involves overriding the class-loader method that loads a class the first time it is required. The overridden method returns a sub-class that is generated at runtime, and includes extra functionality. The library that Spring uses this is 'cglib' which is built on top of 'asm'. . . These libraries prioritize performance over ease-of-use. . . (ease of use not being a concern, since the Spring user doesn't do any byte-code engineering for themselves - just uses the instrumented classes).
AspectJ weaving. This involves using either compile-time weaving or runtime weaving. In the case of the latter a special Java Agent is used (cmd-line argument to the JVM) instead of intercepting the classloader.
Examples of instrumentation are annotation-based transactions, security annotations, validation, etc.
You are observing the second type of instrumentation (a runtime generated sub-class), which is the default for concrete classes. . . (AspectJ can be used in more complex situations, such as providing dependency injection on classes outside of the Spring container).

Categories