mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed3d91b929 | |||
| 731ceb8aca | |||
| 6f213fb6a0 | |||
| 131ae59724 | |||
| dd3b3a7c69 | |||
| cbe79a9241 | |||
| ef4a5fb54c | |||
| 8ffaec5d72 | |||
| 578cdb5f7e | |||
| 305a512a55 | |||
| cf036eeaa3 | |||
| fa8a30f753 | |||
| f63ae425bf | |||
| fa20dd820d | |||
| 01cebc85b4 | |||
| 6cf89a1e58 | |||
| e5e8574466 | |||
| a2cabcbb90 | |||
| 9b3625b39e | |||
| 7232e83807 | |||
| 91afab7723 | |||
| e19a8e58fc | |||
| 5f2707a7e3 | |||
| 92ecef74ec | |||
| 11c9373439 | |||
| 6f8db2cfd3 | |||
| bff8cff03b | |||
| c55979b8a9 | |||
| 097c773b91 | |||
| 431cce0b1e | |||
| 0ed87a350c | |||
| 1a43d698d1 | |||
| 94c5481e9e | |||
| 41675587ea | |||
| b14a20161f | |||
| 10e5029e88 | |||
| 4b2552f498 | |||
| 554f15262d | |||
| 9fc8046728 | |||
| 9b60075085 | |||
| aa2ea2055d | |||
| f9c1e6053c | |||
| 2362a142c1 | |||
| b656bb4855 | |||
| c6eb4c0eae | |||
| 57c6cc83da | |||
| 1943aad216 | |||
| 57b9a57452 | |||
| 35f3e5d664 | |||
| d88eccc837 | |||
| 3f8db79e1c | |||
| e30e453bb4 | |||
| edc01f4957 | |||
| a53a17c01a | |||
| 6c95ee2334 | |||
| 6236ed56e4 | |||
| 6455960cf1 | |||
| 3771743082 | |||
| 1e3b4cdc34 | |||
| 889c9c7de4 | |||
| da97ab1dea | |||
| 9ac9cd15fb | |||
| 621f0a6568 | |||
| 6fb9e4a9ea | |||
| 3881954125 | |||
| 42a4409c73 | |||
| 6c5ef6db1e | |||
| f4ccf68458 | |||
| 4aa824d456 | |||
| 6a68b4d299 | |||
| 28cc8b7a08 | |||
| 317eee83ac | |||
| 81e9a8a26d | |||
| a2337b73e0 | |||
| 8422f0f5b7 | |||
| dc3c016712 |
@@ -0,0 +1,57 @@
|
||||
name: Build and Deploy Documentation
|
||||
run-name: ${{ format('{0} ({1})', github.workflow, github.event.inputs.build-refname || 'all') }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-refname:
|
||||
description: Enter git refname to build (e.g., 5.7.x).
|
||||
required: false
|
||||
push:
|
||||
branches: docs-build
|
||||
env:
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
|
||||
permissions: read-all
|
||||
jobs:
|
||||
build-and-deploy-docs:
|
||||
name: Build and Deploy Documentation
|
||||
if: github.repository_owner == 'spring-projects'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check Out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 5
|
||||
- name: Set Up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'liberica'
|
||||
java-version: |
|
||||
25
|
||||
17
|
||||
- name: Set Up Gradle
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
cache-read-only: false
|
||||
- name: Set up refname build
|
||||
if: github.event.inputs.build-refname
|
||||
run: |
|
||||
git fetch --depth 1 https://github.com/$GITHUB_REPOSITORY ${{ github.event.inputs.build-refname }}
|
||||
echo BUILD_REFNAME=${{ github.event.inputs.build-refname }} >> $GITHUB_ENV
|
||||
echo BUILD_VERSION=$(git cat-file --textconv FETCH_HEAD:gradle.properties | sed -n '/^version=/ { s/^version=//;p }') >> $GITHUB_ENV
|
||||
- name: Run Antora
|
||||
run: ./gradlew antora
|
||||
- name: Copy the cache to be included in the site
|
||||
run: cp -rf build/antora/inject-collector-cache-config-extension/.cache build/site/
|
||||
- name: Publish Docs
|
||||
uses: spring-io/spring-doc-actions/rsync-antora-reference@v0.0.22
|
||||
with:
|
||||
docs-username: ${{ secrets.DOCS_USERNAME }}
|
||||
docs-host: ${{ secrets.DOCS_HOST }}
|
||||
docs-ssh-key: ${{ secrets.DOCS_SSH_KEY }}
|
||||
docs-ssh-host-key: ${{ secrets.DOCS_SSH_HOST_KEY }}
|
||||
- name: Bust Cloudflare Cache
|
||||
uses: spring-io/spring-doc-actions/bust-cloudflare-antora-cache@v0.0.22
|
||||
with:
|
||||
context-root: spring-framework
|
||||
cloudflare-zone-id: ${{ secrets.CLOUDFLARE_ZONE_ID }}
|
||||
cloudflare-cache-token: ${{ secrets.CLOUDFLARE_CACHE_TOKEN }}
|
||||
+39
-9
@@ -1,26 +1,56 @@
|
||||
# Miscellaneous
|
||||
*.java.hsp
|
||||
*.sonarj
|
||||
*.sw*
|
||||
.DS_Store
|
||||
.settings
|
||||
.springBeans
|
||||
bin
|
||||
build.sh
|
||||
integration-repo
|
||||
ivy-cache
|
||||
argfile*
|
||||
activemq-data/
|
||||
classes/
|
||||
|
||||
# Log files
|
||||
jxl.log
|
||||
jmx.log
|
||||
spring-jdbc/derby.log
|
||||
spring-test/test-output/
|
||||
derby.log
|
||||
|
||||
# Gradle artifacts
|
||||
.gradle
|
||||
build
|
||||
.gradletasknamecache
|
||||
/build
|
||||
buildSrc/build
|
||||
/spring-*/build
|
||||
/framework-bom/build
|
||||
/framework-docs/build
|
||||
/integration-tests/build
|
||||
/src/asciidoc/build
|
||||
spring-test/test-output/
|
||||
|
||||
# Maven artifacts
|
||||
pom.xml
|
||||
/target/
|
||||
|
||||
# Eclipse artifacts, including WTP generated manifests
|
||||
bin
|
||||
.classpath
|
||||
.project
|
||||
argfile*
|
||||
pom.xml
|
||||
.settings
|
||||
.springBeans
|
||||
spring-*/src/main/java/META-INF/MANIFEST.MF
|
||||
|
||||
# IDEA metadata and output dirs
|
||||
# IDEA artifacts and output dirs
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea
|
||||
out
|
||||
test-output
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
cached-antora-playbook.yml
|
||||
|
||||
node_modules
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Enable auto-env through the sdkman_auto_env config
|
||||
# Add key=value pairs of SDKs to use below
|
||||
java=17.0.12-librca
|
||||
@@ -1,9 +0,0 @@
|
||||
#com.springsource.sts.gradle.core.preferences.GradleImportPreferences
|
||||
#Thu Aug 9 11:34:43 CEST 2012
|
||||
enableAfterTasks=true
|
||||
afterTasks=afterEclipseImport;
|
||||
enableDependendencyManagement=false
|
||||
enableBeforeTasks=true
|
||||
projects=;spring-aop;spring-aspects;spring-beans;spring-context;spring-context-support;spring-core;spring-expression;spring-instrument;spring-instrument-tomcat;spring-jdbc;spring-jms;spring-orm;spring-oxm;spring-struts;spring-test;spring-tx;spring-web;spring-webmvc;spring-webmvc-portlet;
|
||||
enableDSLD=false
|
||||
beforeTasks=cleanEclipse;eclipse;\:spring-oxm\:compileTestJava;
|
||||
@@ -1,5 +0,0 @@
|
||||
#com.springsource.sts.gradle.core.preferences.GradleProjectPreferences
|
||||
#Tue Feb 21 14:38:31 CET 2012
|
||||
com.springsource.sts.gradle.classpath.enableSorting=false
|
||||
com.springsource.sts.gradle.rootprojectloc=
|
||||
com.springsource.sts.gradle.linkedresources=
|
||||
@@ -1,9 +0,0 @@
|
||||
#com.springsource.sts.gradle.core.actions.GradleRefreshPreferences
|
||||
#Thu Aug 9 11:34:43 CEST 2012
|
||||
enableAfterTasks=true
|
||||
afterTasks=afterEclipseImport;
|
||||
useHierarchicalNames=false
|
||||
enableBeforeTasks=true
|
||||
addResourceFilters=false
|
||||
enableDSLD=false
|
||||
beforeTasks=cleanEclipse;eclipse;\:spring-oxm\:compileTestJava;
|
||||
-307
@@ -1,307 +0,0 @@
|
||||
_Have something you'd like to contribute to the framework? We welcome pull
|
||||
requests, but ask that you carefully read this document first to understand how
|
||||
best to submit them; what kind of changes are likely to be accepted; and what
|
||||
to expect from the Spring team when evaluating your submission._
|
||||
|
||||
_Please refer back to this document as a checklist before issuing any pull
|
||||
request; this will save time for everyone!_
|
||||
|
||||
## Understand the basics
|
||||
|
||||
Not sure what a pull request is, or how to submit one? Take a look at GitHub's
|
||||
excellent [help documentation][] first.
|
||||
|
||||
|
||||
## Search JIRA first; create an issue if necessary
|
||||
|
||||
Is there already an issue that addresses your concern? Do a bit of searching
|
||||
in our [JIRA issue tracker][] to see if you can find something similar. If not,
|
||||
please create a new issue before submitting a pull request unless the change is
|
||||
truly trivial, e.g. typo fixes, removing compiler warnings, etc.
|
||||
|
||||
## Discuss non-trivial contribution ideas with committers
|
||||
|
||||
If you're considering anything more than correcting a typo or fixing a minor
|
||||
bug, please discuss it on the [spring-framework-contrib][] mailing list before
|
||||
submitting a pull request. We're happy to provide guidance but please spend an
|
||||
hour or two researching the subject on your own including searching the mailing
|
||||
list for prior discussions.
|
||||
|
||||
## Sign the Contributor License Agreement
|
||||
|
||||
If you have not previously done so, please fill out and submit the
|
||||
[SpringSource CLA form][]. You'll receive a token when this process is complete.
|
||||
Keep track of this, you may be asked for it later!
|
||||
|
||||
Note that emailing/postal mailing a signed copy is _not_ necessary. Submission
|
||||
of the web form is all that is required.
|
||||
|
||||
When you've completed the web form, simply add the following in a comment on
|
||||
your pull request:
|
||||
|
||||
I have signed and agree to the terms of the SpringSource Individual
|
||||
Contributor License Agreement.
|
||||
|
||||
You do not need to include your token/id. Please add the statement above to all
|
||||
future pull requests as well, simply so the Spring Framework team knows
|
||||
immediately that this process is complete.
|
||||
|
||||
|
||||
## Create your branch from `master`
|
||||
|
||||
At any given time, Spring Framework's `master` branch represents the version
|
||||
currently under development. For example, if 3.1.1 was the latest Spring
|
||||
Framework release, `master` represents 3.2.0 development, and the `3.1.x`
|
||||
branch represents 3.1.2 development.
|
||||
|
||||
Create your topic branch to be submitted as a pull request from `master`. The
|
||||
Spring team will consider your pull request for backporting to maintenance
|
||||
versions (e.g. 3.1.2) on a case-by-case basis; you don't need to worry about
|
||||
submitting anything for backporting.
|
||||
|
||||
|
||||
## Use short branch names
|
||||
|
||||
Branches used when submitting pull requests should preferably be named
|
||||
according to JIRA issues, e.g. 'SPR-1234'. Otherwise, use succinct, lower-case,
|
||||
dash (-) delimited names, such as 'fix-warnings', 'fix-typo', etc. In
|
||||
[fork-and-edit][] cases, the GitHub default 'patch-1' is fine as well. This is
|
||||
important, because branch names show up in the merge commits that result from
|
||||
accepting pull requests, and should be as expressive and concise as possible.
|
||||
|
||||
|
||||
## Mind the whitespace
|
||||
|
||||
Please carefully follow the whitespace and formatting conventions already
|
||||
present in the framework.
|
||||
|
||||
1. Tabs, not spaces
|
||||
1. Unix (LF), not dos (CRLF) line endings
|
||||
1. Eliminate all trailing whitespace
|
||||
1. Wrap Javadoc at 90 characters
|
||||
1. Aim to wrap code at 90 characters, but favor readability over wrapping
|
||||
1. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
1. Search the codebase using `git grep` and other tools to discover common
|
||||
naming conventions, etc.
|
||||
1. Latin-1 (ISO-8859-1) encoding for Java sources; use `native2ascii` to convert
|
||||
if necessary
|
||||
|
||||
|
||||
## Add Apache license header to all new classes
|
||||
|
||||
```java
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ...;
|
||||
```
|
||||
|
||||
## Update Apache license header to modified files as necessary
|
||||
|
||||
Always check the date range in the license header. For example, if you've
|
||||
modified a file in 2012 whose header still reads
|
||||
|
||||
```java
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
```
|
||||
|
||||
then be sure to update it to 2012 appropriately
|
||||
|
||||
```java
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
```
|
||||
|
||||
## Use @since tags for newly-added public API types and methods
|
||||
|
||||
e.g.
|
||||
|
||||
```java
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @author First Last
|
||||
* @since 3.2
|
||||
* @see ...
|
||||
*/
|
||||
```
|
||||
|
||||
## Submit JUnit test cases for all behavior changes
|
||||
|
||||
Search the codebase to find related unit tests and add additional @Test methods
|
||||
within. It is also acceptable to submit test cases on a per JIRA issue basis,
|
||||
e.g.
|
||||
|
||||
```java
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
/**
|
||||
* Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor}
|
||||
* forces the predicted type of a FactoryBean, effectively preventing retrieval of the
|
||||
* bean from calls to #getBeansOfType(FactoryBean.class). The implementation of
|
||||
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures
|
||||
* that not only the predicted bean type is considered, but also the original bean
|
||||
* definition's beanClass.
|
||||
*
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class Spr8954Tests {
|
||||
|
||||
@Test
|
||||
public void cornerSpr8954() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Squash commits
|
||||
|
||||
Use `git rebase --interactive`, `git add --patch` and other tools to "squash"
|
||||
multiple commits into atomic changes. In addition to the man pages for git,
|
||||
there are many resources online to help you understand how these tools work.
|
||||
Here is one: http://book.git-scm.com/4_interactive_rebasing.html.
|
||||
|
||||
|
||||
## Use real name in git commits
|
||||
|
||||
Please configure git to use your real first and last name for any commits you
|
||||
intend to submit as pull requests. For example, this is not acceptable:
|
||||
|
||||
Author: Nickname <user@mail.com>
|
||||
|
||||
Rather, please include your first and last name, properly capitalized, as
|
||||
submitted against the SpringSource contributor license agreement:
|
||||
|
||||
Author: First Last <user@mail.com>
|
||||
|
||||
This helps ensure traceability against the CLA, and also goes a long way to
|
||||
ensuring useful output from tools like `git shortlog` and others.
|
||||
|
||||
You can configure this globally via the account admin area GitHub (useful for
|
||||
fork-and-edit cases); globally with
|
||||
|
||||
git config --global user.name "First Last"
|
||||
git config --global user.email user@mail.com
|
||||
|
||||
or locally for the spring-framework repository only by omitting the '--global'
|
||||
flag:
|
||||
|
||||
cd spring-framework
|
||||
git config user.name "First Last"
|
||||
git config user.email user@mail.com
|
||||
|
||||
|
||||
## Format commit messages
|
||||
|
||||
Please read and follow the [commit guidelines section of Pro Git][].
|
||||
|
||||
Most importantly, please format your commit messages in the following way
|
||||
(adapted from the commit template in the link above):
|
||||
|
||||
Short (50 chars or less) summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of an email and the rest of the text as the body. The blank
|
||||
line separating the summary from the body is critical (unless you omit
|
||||
the body entirely); tools like rebase can get confused if you run the
|
||||
two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded by a
|
||||
single space, with blank lines in between, but conventions vary here
|
||||
|
||||
Issue: SPR-1234, SPR-1235
|
||||
|
||||
|
||||
1. Use imperative statements in the subject line, e.g. "Fix broken Javadoc link"
|
||||
1. Begin the subject line sentence with a capitalized verb, e.g. "Add, Prune,
|
||||
Fix, Introduce, Avoid, etc"
|
||||
1. Do not end the subject line with a period
|
||||
1. Keep the subject line to 50 characters or less if possible
|
||||
1. Wrap lines in the body at 72 characters or less
|
||||
1. Mention associated jira issue(s) at the end of the commit comment, prefixed
|
||||
with "Issue: " as above
|
||||
1. In the body of the commit message, explain how things worked before this
|
||||
commit, what has changed, and how things work now
|
||||
|
||||
For examples of this style, issue a `git log --author=cbeams` in the
|
||||
spring-framework git repository. For convenience, here are several such commits:
|
||||
|
||||
https://github.com/SpringSource/spring-framework/commit/08e2669b84ec0faa2f7904441fe39ac70b65b078
|
||||
https://github.com/SpringSource/spring-framework/commit/1d9d3e6ff79ce9f0eca03b02cd1df705925575da
|
||||
https://github.com/SpringSource/spring-framework/commit/8e0b1c3a5f957af3049cfa0438317177e16d6de6
|
||||
https://github.com/SpringSource/spring-framework/commit/b787a68f2050df179f7036b209aa741230a02477
|
||||
|
||||
## Run all tests prior to submission
|
||||
|
||||
See the [building from source][] section of the README for instructions. Make
|
||||
sure that all tests pass prior to submitting your pull request.
|
||||
|
||||
|
||||
## Submit your pull request
|
||||
|
||||
Subject line:
|
||||
|
||||
Follow the same conventions for pull request subject lines as mentioned above
|
||||
for commit message subject lines.
|
||||
|
||||
In the body:
|
||||
|
||||
1. Explain your use case. What led you to submit this change? Why were existing
|
||||
mechanisms in the framework insufficient? Make a case that this is a
|
||||
general-purpose problem and that yours is a general-purpose solution, etc.
|
||||
1. Add any additional information and ask questions; start a conversation, or
|
||||
continue one from JIRA
|
||||
1. Mention the JIRA issue ID
|
||||
1. Also mention that you have submitted the CLA as described above
|
||||
|
||||
Note that for pull requests containing a single commit, GitHub will default the
|
||||
subject line and body of the pull request to match the subject line and body of
|
||||
the commit message. This is fine, but please also include the items above in the
|
||||
body of the request.
|
||||
|
||||
|
||||
## Mention your pull request on the associated JIRA issue
|
||||
|
||||
Add a comment to the associated JIRA issue(s) linking to your new pull request.
|
||||
|
||||
|
||||
## Expect discussion and rework
|
||||
|
||||
The Spring team takes a very conservative approach to accepting contributions to
|
||||
the framework. This is to keep code quality and stability as high as possible,
|
||||
and to keep complexity at a minimum. Your changes, if accepted, may be heavily
|
||||
modified prior to merging. You will retain "Author:" attribution for your Git
|
||||
commits granted that the bulk of your changes remain intact. You may be asked to
|
||||
rework the submission for style (as explained above) and/or substance. Again, we
|
||||
strongly recommend discussing any serious submissions with the Spring Framework
|
||||
team _prior_ to engaging in serious development work.
|
||||
|
||||
Note that you can always force push (`git push -f`) reworked / rebased commits
|
||||
against the branch used to submit your pull request. i.e. you do not need to
|
||||
issue a new pull request when asked to make changes.
|
||||
|
||||
[help documentation]: http://help.github.com/send-pull-requests
|
||||
[JIRA issue tracker]: https://jira.springsource.org/browse/SPR
|
||||
[spring-framework-contrib]: https://groups.google.com/forum/#!forum/spring-framework-contrib
|
||||
[SpringSource CLA form]: https://support.springsource.com/spring_committer_signup
|
||||
[fork-and-edit]: https://github.com/blog/844-forking-with-the-edit-button
|
||||
[commit guidelines section of Pro Git]: http://progit.org/book/ch5-2.html#commit_guidelines
|
||||
[building from source]: https://github.com/SpringSource/spring-framework#building-from-source
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
= Spring Framework Docs Build
|
||||
|
||||
You're currently viewing the Antora playbook branch.
|
||||
The playbook branch hosts the docs build that is used to build and publish the production docs site.
|
||||
|
||||
The Spring Framework reference docs are built using https://antora.org[Antora].
|
||||
This README covers how to build the docs in a software branch as well as how to build the production docs site locally.
|
||||
|
||||
== Overview
|
||||
|
||||
To prepare your system for building the documentation, <<prerequisites,install the prerequisites>> and then <<build-main,create your workspace and build the main branch documentation>>.
|
||||
Once you've completed those steps, follow the instructions in <<build-branch,Build the 6.0.x branch documentation>> to learn how to build the documentation for a version branch you haven't previously checked out.
|
||||
|
||||
To build the production site documentation on your computer, follow the instructions in <<prerequisites,Prerequisites>>, <<build-main,Build the main branch documentation>>, and then <<build-production,Build the production documentation site>>.
|
||||
|
||||
.Branch checkout instead of worktrees
|
||||
[NOTE]
|
||||
====
|
||||
If you prefer to set up your workspace without worktrees, complete the steps in <<prerequisites,Prerequisites>> and clone the project repository onto your computer.
|
||||
Then follow the instructions in each section starting from the `sdk env || sdk env install` step once you've checked out the desired branch.
|
||||
====
|
||||
|
||||
[#prerequisites]
|
||||
== Prerequisites (everyone)
|
||||
|
||||
These instructions assume you already have basic tools on your system, including bash, zip, unzip, git, and curl.
|
||||
In addition to these basic tools, you need https://sdkman.io/install[SDKMAN!] installed so that the correct JDK is set for each branch.
|
||||
|
||||
. Open your terminal and enter the following command:
|
||||
+
|
||||
--
|
||||
$ curl -s "https://get.sdkman.io" | bash
|
||||
|
||||
This command downloads and installs SDKMAN!
|
||||
Once installation is complete, you should see a command displayed in your terminal that will initiate SDKMAN.
|
||||
--
|
||||
|
||||
. Copy the command displayed in your terminal and run it.
|
||||
`$HOME` is the path unique to your computer (e.g., _home/my-jam/.sdkman/bin/sdkman-init.sh_).
|
||||
|
||||
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
|
||||
|
||||
You'll use SDKMAN in the next sections to install and switch to the JDK required for each branch.
|
||||
Now you're ready to <<build-main,create your workspace>>.
|
||||
|
||||
[#build-main]
|
||||
== Build the main branch documentation (writers)
|
||||
|
||||
Your workspace will be the folder that contains the git worktrees of the project.
|
||||
|
||||
. In your terminal, create a directory for the project and then change into that directory.
|
||||
|
||||
$ mkdir spring-framework
|
||||
$ cd spring-framework
|
||||
|
||||
. Clone the project repository and create the primary worktree for the main branch.
|
||||
Then change into the new _main_ folder.
|
||||
|
||||
$ git clone https://github.com/spring-projects/spring-framework main
|
||||
$ cd main
|
||||
|
||||
. Switch to the required JDK using SDKMAN by running the following command:
|
||||
+
|
||||
--
|
||||
$ sdk env || sdk env install
|
||||
|
||||
SDKMAN will switch to the required JDK or install it if it isn't present.
|
||||
--
|
||||
|
||||
. Generate the documentation with Antora using the following command:
|
||||
+
|
||||
--
|
||||
$ ./gradlew -PbuildSrc.skipTests=true :framework-docs:antora
|
||||
|
||||
This command will build the documentation, including any generated attributes, for the main branch.
|
||||
--
|
||||
|
||||
. Navigate to _$HOME/spring-framework/main/framework-docs/build/site/index.html_ to view the generated documentation.
|
||||
|
||||
[#build-branch]
|
||||
== Build the 6.0.x branch documentation (writers)
|
||||
|
||||
NOTE: The instructions in this section assume you've completed the steps in the <<build-main,previous section>>.
|
||||
|
||||
After creating the worktree for the main branch, you can set up a worktree for any other branches you'll work on in the future.
|
||||
In this section, you'll create a worktree for the 6.0.x branch in your project workspace.
|
||||
|
||||
. To add a worktree, you have to be in a worktree.
|
||||
In your terminal, change to the _main_ folder if you aren't already in it, e.g., _$HOME/spring-framework/main_.
|
||||
Set up a worktree for the 6.0.x branch and then change into the new directory by running the following commands:
|
||||
|
||||
$ git worktree add ../6.0.x 6.0.x --track
|
||||
$ cd ../6.0.x
|
||||
|
||||
. Switch to the required JDK or install it.
|
||||
|
||||
$ sdk env || sdk env install
|
||||
|
||||
. Generate the documentation with the following command:
|
||||
+
|
||||
--
|
||||
$ ./gradlew -PbuildSrc.skipTests=true :framework-docs:antora
|
||||
|
||||
This command will build the documentation, including any generated attributes, for the 6.0.x branch.
|
||||
--
|
||||
|
||||
. Navigate to _$HOME/spring-framework/6.0.x/docs/build/site/index.html_ to view the generated documentation.
|
||||
|
||||
[#build-production]
|
||||
== Build the production documentation site (docs manager)
|
||||
|
||||
NOTE: The instructions in this section assume you've <<build-main,prepared your workspace and created the worktree for the main branch>>.
|
||||
|
||||
To build the project's production site, you'll set up a worktree for the docs-build branch of the repository.
|
||||
|
||||
. To add a worktree, you have to be in a worktree.
|
||||
In your terminal, change to the _main_ folder if you aren't already in it, e.g., _$HOME/spring-framework/main_.
|
||||
Run the following command to set up the worktree for the _docs-build_ branch.
|
||||
Then change into the new _docs-build_ directory.
|
||||
|
||||
$ git worktree add ../docs-build docs-build --track
|
||||
$ cd ../docs-build
|
||||
|
||||
. Switch to the required JDK or install it.
|
||||
|
||||
$ sdk env || sdk env install
|
||||
|
||||
. Generate the documentation for the project's production site using the following command:
|
||||
+
|
||||
--
|
||||
$ ./gradlew antora
|
||||
|
||||
This command will build all of the documentation included in the project's production site from the repository on GitHub.
|
||||
|
||||
To build the documentation from the current clone, using any worktrees that are available, use the following command instead:
|
||||
|
||||
$ ./gradlew antora --playbook local-antora-playbook.yml
|
||||
--
|
||||
|
||||
. Navigate to _$HOME/spring-framework/docs-site/build/site/index.html_ to view the generated documentation.
|
||||
@@ -1,96 +0,0 @@
|
||||
## Spring Framework
|
||||
The Spring Framework provides a comprehensive programming and configuration
|
||||
model for modern Java-based enterprise applications - on any kind of deployment
|
||||
platform. A key element of Spring is infrastructural support at the application
|
||||
level: Spring focuses on the "plumbing" of enterprise applications so that teams
|
||||
can focus on application-level business logic, without unnecessary ties to
|
||||
specific deployment environments.
|
||||
|
||||
The framework also serves as the foundation for [Spring Integration][], [Spring
|
||||
Batch][] and the rest of the Spring [family of projects][]. Browse the
|
||||
repositories under the [SpringSource organization][] on GitHub for a full list.
|
||||
|
||||
[.NET][] and [Python][] variants are available as well.
|
||||
|
||||
## Downloading artifacts
|
||||
See [downloading Spring artifacts][] for Maven repository information. Unable to
|
||||
use Maven or other transitive dependency management tools? See [building a
|
||||
distribution with dependencies][].
|
||||
|
||||
## Documentation
|
||||
See the current [Javadoc][] and [reference docs][].
|
||||
|
||||
## Getting support
|
||||
Check out the [Spring forums][] and the [spring][spring tag] and
|
||||
[spring-mvc][spring-mvc tag] tags on [Stack Overflow][]. [Commercial support][]
|
||||
is available too.
|
||||
|
||||
## Issue Tracking
|
||||
Report issues via the [Spring Framework JIRA]. Understand our issue management
|
||||
process by reading about [the lifecycle of an issue][]. Think you've found a
|
||||
bug? Please consider submitting a reproduction project via the
|
||||
[spring-framework-issues][] GitHub repository. The [readme][] there provides
|
||||
simple step-by-step instructions.
|
||||
|
||||
## Building from source
|
||||
The Spring Framework uses a [Gradle][]-based build system. In the instructions
|
||||
below, [`./gradlew`][] is invoked from the root of the source tree and serves as
|
||||
a cross-platform, self-contained bootstrap mechanism for the build. The only
|
||||
prerequisites are [Git][] and JDK 1.7+.
|
||||
|
||||
### check out sources
|
||||
`git clone git://github.com/SpringSource/spring-framework.git`
|
||||
|
||||
### compile and test, build all jars, distribution zips and docs
|
||||
`./gradlew build`
|
||||
|
||||
### install all spring-\* jars into your local Maven cache
|
||||
`./gradlew install`
|
||||
|
||||
### import sources into your IDE
|
||||
Run `./import-into-eclipse.sh` or read `import-into-idea.md` as appropriate.
|
||||
|
||||
... and discover more commands with `./gradlew tasks`. See also the [Gradle
|
||||
build and release FAQ][].
|
||||
|
||||
## Contributing
|
||||
[Pull requests][] are welcome; see the [contributor guidelines][] for details.
|
||||
|
||||
## Staying in touch
|
||||
Follow [@springframework][] and its [team members][] on Twitter. In-depth
|
||||
articles can be found at the SpringSource [team blog][], and releases are
|
||||
announced via our [news feed][].
|
||||
|
||||
## License
|
||||
The Spring Framework is released under version 2.0 of the [Apache License][].
|
||||
|
||||
[Spring Integration]: https://github.com/SpringSource/spring-integration
|
||||
[Spring Batch]: https://github.com/SpringSource/spring-batch
|
||||
[family of projects]: http://springsource.org/projects
|
||||
[SpringSource organization]: https://github.com/SpringSource
|
||||
[.NET]: https://github.com/SpringSource/spring-net
|
||||
[Python]: https://github.com/SpringSource/spring-python
|
||||
[downloading Spring artifacts]: https://github.com/SpringSource/spring-framework/wiki/Downloading-Spring-artifacts
|
||||
[building a distribution with dependencies]: https://github.com/SpringSource/spring-framework/wiki/Building-a-distribution-with-dependencies
|
||||
[Javadoc]: http://static.springsource.org/spring-framework/docs/current/javadoc-api
|
||||
[reference docs]: http://static.springsource.org/spring-framework/docs/current/spring-framework-reference
|
||||
[Spring forums]: http://forum.springsource.org
|
||||
[spring tag]: http://stackoverflow.com/questions/tagged/spring
|
||||
[spring-mvc tag]: http://stackoverflow.com/questions/tagged/spring-mvc
|
||||
[Stack Overflow]: http://stackoverflow.com/faq
|
||||
[Commercial support]: http://springsource.com/support/springsupport
|
||||
[Spring Framework JIRA]: http://jira.springsource.org/browse/SPR
|
||||
[the lifecycle of an issue]: https://github.com/cbeams/spring-framework/wiki/The-Lifecycle-of-an-Issue
|
||||
[spring-framework-issues]: https://github.com/SpringSource/spring-framework-issues#readme
|
||||
[readme]: https://github.com/SpringSource/spring-framework-issues#readme
|
||||
[Gradle]: http://gradle.org
|
||||
[`./gradlew`]: http://vimeo.com/34436402
|
||||
[Git]: http://help.github.com/set-up-git-redirect
|
||||
[Gradle build and release FAQ]: https://github.com/SpringSource/spring-framework/wiki/Gradle-build-and-release-FAQ
|
||||
[Pull requests]: http://help.github.com/send-pull-requests
|
||||
[contributor guidelines]: https://github.com/SpringSource/spring-framework/blob/master/CONTRIBUTING.md
|
||||
[@springframework]: http://twitter.com/springframework
|
||||
[team members]: http://twitter.com/springframework/team/members
|
||||
[team blog]: http://blog.springsource.org
|
||||
[news feed]: http://www.springsource.org/news-events
|
||||
[Apache License]: http://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1,41 @@
|
||||
antora:
|
||||
extensions:
|
||||
- require: '@springio/antora-extensions'
|
||||
root_component_name: 'framework'
|
||||
site:
|
||||
title: Spring Framework
|
||||
url: https://docs.spring.io/spring-framework/reference
|
||||
robots: allow
|
||||
git:
|
||||
ensure_git_suffix: false
|
||||
content:
|
||||
sources:
|
||||
- url: https://github.com/spring-projects/spring-framework
|
||||
# Refname matching:
|
||||
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
|
||||
# branches: We include snapshots for main, 6.2.x, and 7.0.x to 9.*.x.
|
||||
branches: ['main', '6.2.x', '{7..9}.+({0..9}).x']
|
||||
# tags: include all releases from 6.2.0 to 9.*.*.
|
||||
tags: ['v6.2.+({0..9})', 'v{7..9}.+({0..9}).+({0..9})?(-{RC,M}*)']
|
||||
start_path: framework-docs
|
||||
asciidoc:
|
||||
extensions:
|
||||
- '@asciidoctor/tabs'
|
||||
- '@springio/asciidoctor-extensions'
|
||||
- '@springio/asciidoctor-extensions/include-code-extension'
|
||||
attributes:
|
||||
page-stackoverflow-url: https://stackoverflow.com/questions/tagged/spring
|
||||
page-pagination: ''
|
||||
hide-uri-scheme: '@'
|
||||
tabs-sync-option: '@'
|
||||
include-java: 'example$docs-src/main/java/org/springframework/docs'
|
||||
urls:
|
||||
latest_version_segment_strategy: redirect:to
|
||||
latest_version_segment: ''
|
||||
redirect_facility: httpd
|
||||
runtime:
|
||||
log:
|
||||
failure_level: warn
|
||||
ui:
|
||||
bundle:
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.26/ui-bundle.zip
|
||||
+7
-886
@@ -1,891 +1,12 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "http://repo.springsource.org/plugins-release" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.1")
|
||||
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.4")
|
||||
}
|
||||
plugins {
|
||||
id 'base'
|
||||
id 'org.antora' version '1.0.0'
|
||||
}
|
||||
|
||||
configure(allprojects) {
|
||||
ext.aspectjVersion = "1.7.1"
|
||||
ext.easymockVersion = "2.5.2"
|
||||
ext.hsqldbVersion = "1.8.0.10"
|
||||
ext.junitVersion = "4.11"
|
||||
ext.slf4jVersion = "1.6.1"
|
||||
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
|
||||
|
||||
apply plugin: "propdeps"
|
||||
apply plugin: "java"
|
||||
apply plugin: "propdeps-eclipse"
|
||||
apply plugin: "propdeps-idea"
|
||||
apply from: "${gradleScriptDir}/ide.gradle"
|
||||
|
||||
group = "org.springframework"
|
||||
|
||||
sourceCompatibility=1.5
|
||||
targetCompatibility=1.5
|
||||
|
||||
[compileJava, compileTestJava]*.options*.compilerArgs = ["-Xlint:none"]
|
||||
|
||||
sourceSets.test.resources.srcDirs = ["src/test/resources", "src/test/java"]
|
||||
|
||||
test.systemProperty("java.awt.headless", "true")
|
||||
|
||||
repositories {
|
||||
maven { url "http://repo.springsource.org/libs-release" }
|
||||
maven { url "http://repo.springsource.org/ebr-maven-external" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile("junit:junit:${junitVersion}")
|
||||
testCompile("org.hamcrest:hamcrest-all:1.3")
|
||||
testCompile("org.easymock:easymock:${easymockVersion}")
|
||||
}
|
||||
|
||||
ext.javadocLinks = [
|
||||
"http://docs.oracle.com/javase/6/docs/api",
|
||||
"http://docs.oracle.com/javaee/6/api",
|
||||
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
|
||||
"http://commons.apache.org/lang/api-2.5",
|
||||
"http://commons.apache.org/codec/apidocs",
|
||||
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector",
|
||||
"http://docs.jboss.org/jbossas/javadoc/7.1.2.Final",
|
||||
"http://aopalliance.sourceforge.net/doc",
|
||||
"http://glassfish.java.net/nonav/docs/v3/api",
|
||||
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs", // commonj
|
||||
"http://quartz-scheduler.org/api/2.1.5",
|
||||
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
|
||||
"http://hc.apache.org/httpclient-3.x/apidocs",
|
||||
"http://fasterxml.github.com/jackson-core/javadoc/2.0.0",
|
||||
"http://jackson.codehaus.org/1.4.2/javadoc",
|
||||
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs",
|
||||
"http://ibatis.apache.org/docs/java/dev",
|
||||
"http://tiles.apache.org/framework/apidocs",
|
||||
"http://commons.apache.org/dbcp/api-1.2.2",
|
||||
] as String[]
|
||||
antora {
|
||||
options = [clean: true, fetch: true, stacktrace: true]
|
||||
}
|
||||
|
||||
configure(subprojects) { subproject ->
|
||||
apply plugin: "merge"
|
||||
apply from: "${gradleScriptDir}/publish-maven.gradle"
|
||||
|
||||
jar {
|
||||
manifest.attributes["Created-By"] =
|
||||
"${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})"
|
||||
manifest.attributes["Implementation-Title"] = subproject.name
|
||||
manifest.attributes["Implementation-Version"] = subproject.version
|
||||
|
||||
from("${rootProject.projectDir}/src/dist") {
|
||||
include "license.txt"
|
||||
include "notice.txt"
|
||||
into "META-INF"
|
||||
expand(copyright: new Date().format("yyyy"), version: project.version)
|
||||
}
|
||||
}
|
||||
|
||||
javadoc {
|
||||
description = "Generates project-level javadoc for use in -javadoc jar"
|
||||
|
||||
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
|
||||
options.author = true
|
||||
options.header = project.name
|
||||
options.links(project.ext.javadocLinks)
|
||||
|
||||
// suppress warnings due to cross-module @see and @link references;
|
||||
// note that global 'api' task does display all warnings.
|
||||
logging.captureStandardError LogLevel.INFO
|
||||
logging.captureStandardOutput LogLevel.INFO // suppress "## warnings" message
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn:classes) {
|
||||
classifier = "sources"
|
||||
from sourceSets.main.allJava.srcDirs
|
||||
include "**/*.java", "**/*.aj"
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
classifier = "javadoc"
|
||||
from javadoc
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
project("spring-core") {
|
||||
description = "Spring Core"
|
||||
|
||||
// As of Spring 3.2 spring-core repackages both asm 4.0 and cglib 3.0 and inlines both
|
||||
// into the spring-core jar. cglib 3.0 itself depends on asm 4.0, and is therefore
|
||||
// further transformed by the JarJar task to depend on org.springframework.asm; this
|
||||
// avoids including two different copies of asm unnecessarily. If however future cglib
|
||||
// versions drift from the version of asm used by Spring internally, this duplication
|
||||
// will become necessary.
|
||||
def asmVersion = "4.0"
|
||||
def cglibVersion = "3.0"
|
||||
|
||||
configurations {
|
||||
jarjar
|
||||
asm
|
||||
cglib
|
||||
}
|
||||
|
||||
task asmRepackJar(type: Jar) { repackJar ->
|
||||
repackJar.baseName = "spring-asm-repack"
|
||||
repackJar.version = asmVersion
|
||||
|
||||
doLast() {
|
||||
project.ant {
|
||||
taskdef name: "jarjar", classname: "com.tonicsystems.jarjar.JarJarTask",
|
||||
classpath: configurations.jarjar.asPath
|
||||
jarjar(destfile: repackJar.archivePath) {
|
||||
configurations.asm.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task cglibRepackJar(type: Jar) { repackJar ->
|
||||
repackJar.baseName = "spring-cglib-repack"
|
||||
repackJar.version = cglibVersion
|
||||
|
||||
doLast() {
|
||||
project.ant {
|
||||
taskdef name: "jarjar", classname: "com.tonicsystems.jarjar.JarJarTask",
|
||||
classpath: configurations.jarjar.asPath
|
||||
jarjar(destfile: repackJar.archivePath) {
|
||||
configurations.cglib.each { originalJar ->
|
||||
zipfileset(src: originalJar)
|
||||
}
|
||||
// repackage net.sf.cglib => org.springframework.cglib
|
||||
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
|
||||
// as mentioned above, transform cglib"s internal asm dependencies from
|
||||
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
|
||||
// the fact that Spring and cglib depend on the same version of asm!
|
||||
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
asm("org.ow2.asm:asm:${asmVersion}@jar")
|
||||
asm("org.ow2.asm:asm-commons:${asmVersion}@jar")
|
||||
cglib("cglib:cglib:${cglibVersion}@jar")
|
||||
jarjar("com.googlecode.jarjar:jarjar:1.3")
|
||||
|
||||
compile(files(asmRepackJar))
|
||||
compile("commons-logging:commons-logging:1.1.1")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("net.sf.jopt-simple:jopt-simple:3.0")
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile("xmlunit:xmlunit:1.2")
|
||||
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7")
|
||||
}
|
||||
|
||||
jar {
|
||||
// inline all repackaged asm and cglib classes directly into the spring-core jar
|
||||
dependsOn asmRepackJar
|
||||
from(zipTree(asmRepackJar.archivePath)) {
|
||||
include "org/springframework/asm/**"
|
||||
}
|
||||
dependsOn cglibRepackJar
|
||||
from(zipTree(cglibRepackJar.archivePath)) {
|
||||
include "org/springframework/cglib/**"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-beans") {
|
||||
description = "Spring Beans"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
provided("javax.el:el-api:1.0")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
testCompile("log4j:log4j:1.2.17")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-aop") {
|
||||
description = "Spring AOP"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
compile(project(":spring-beans"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("com.jamonapi:jamon:2.4")
|
||||
optional("commons-pool:commons-pool:1.5.3")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-expression") {
|
||||
description = "Spring Expression Language (SpEL)"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-instrument") {
|
||||
description = "Spring Instrument"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
}
|
||||
jar {
|
||||
manifest.attributes["Premain-Class"] =
|
||||
"org.springframework.instrument.InstrumentationSavingAgent"
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-instrument-tomcat") {
|
||||
description = "Spring Instrument Tomcat"
|
||||
dependencies {
|
||||
provided("org.apache.tomcat:catalina:6.0.16")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-context") {
|
||||
description = "Spring Context"
|
||||
dependencies {
|
||||
optional(project(":spring-instrument"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-core"))
|
||||
compile(files(project(":spring-core").cglibRepackJar))
|
||||
optional("backport-util-concurrent:backport-util-concurrent:3.0")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
optional("javax.inject:javax.inject:1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("javax.validation:validation-api:1.0.0.GA")
|
||||
optional("org.beanshell:bsh:2.0b4")
|
||||
optional("org.codehaus.groovy:groovy-all:1.8.8")
|
||||
optional("org.jruby:jruby:1.6.5.1")
|
||||
optional("joda-time:joda-time:2.1")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
optional("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
testCompile("javax.inject:com.springsource.org.atinject.tck:1.0.0")
|
||||
}
|
||||
|
||||
test {
|
||||
jvmArgs = ["-disableassertions:org.aspectj.weaver.UnresolvedType"] // SPR-7989
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-tx") {
|
||||
description = "Spring Transaction"
|
||||
dependencies {
|
||||
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
|
||||
optional(project(":spring-aop"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
provided("com.ibm.websphere:uow:6.0.2.17")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.ejb:ejb-api:3.0")
|
||||
testCompile "org.easymock:easymockclassextension:${easymockVersion}"
|
||||
testCompile("javax.persistence:persistence-api:1.0")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-oxm") {
|
||||
description = "Spring Object/XML Marshalling"
|
||||
apply from: "oxm.gradle"
|
||||
dependencies {
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-context")) // for Jaxb2Marshaller
|
||||
compile("commons-lang:commons-lang:2.5")
|
||||
optional("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
optional("com.sun.xml.bind:jaxb-impl:2.1.7")
|
||||
optional("org.jibx:jibx-run:1.2.3")
|
||||
optional("org.apache.xmlbeans:xmlbeans:2.4.0")
|
||||
optional("org.codehaus.castor:castor-xml:1.3.2")
|
||||
testCompile("org.codehaus.jettison:jettison:1.0.1")
|
||||
testCompile("xmlunit:xmlunit:1.2")
|
||||
testCompile("xmlpull:xmlpull:1.1.3.4a")
|
||||
testCompile(files(genCastor.classesDir).builtBy(genCastor))
|
||||
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
|
||||
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-jms") {
|
||||
description = "Spring JMS"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-aop"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
optional(project(":spring-oxm"))
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
provided("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
optional("javax.resource:connector-api:1.5")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-jdbc") {
|
||||
description = "Spring JDBC"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-context")) // for JndiDataSourceLookup
|
||||
compile(project(":spring-tx"))
|
||||
optional("c3p0:c3p0:0.9.1.2")
|
||||
optional("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
optional("com.h2database:h2:1.0.71")
|
||||
optional("org.apache.derby:derby:10.5.3.0_1")
|
||||
optional("org.apache.derby:derbyclient:10.5.3.0_1")
|
||||
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-context-support") {
|
||||
description = "Spring Context Support"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
optional(project(":spring-jdbc")) // for Quartz support
|
||||
optional(project(":spring-tx")) // for Quartz support
|
||||
optional("javax.mail:mail:1.4")
|
||||
optional("javax.cache:cache-api:0.5")
|
||||
optional("net.sf.ehcache:ehcache-core:2.0.0")
|
||||
optional("opensymphony:quartz:1.6.2")
|
||||
optional("org.codehaus.fabric3.api:commonj:1.1.0")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("org.freemarker:freemarker:2.3.15")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("jasperreports:jasperreports:2.0.5")
|
||||
optional("org.slf4j:slf4j-api:${slf4jVersion}")
|
||||
provided("javax.activation:activation:1.1")
|
||||
testCompile("org.apache.poi:poi:3.0.2-FINAL")
|
||||
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
|
||||
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
|
||||
// pick up **/*.types files in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
}
|
||||
|
||||
project("spring-web") {
|
||||
description = "Spring Web"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans")) // for MultiPartFilter
|
||||
compile(project(":spring-aop")) // for JaxWsPortProxyFactoryBean
|
||||
compile(project(":spring-context"))
|
||||
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("com.caucho:hessian:3.2.1")
|
||||
optional("rome:rome:1.0")
|
||||
optional("javax.el:el-api:1.0")
|
||||
optional("javax.faces:jsf-api:1.2_08")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.xml:jaxrpc-api:1.1")
|
||||
provided("javax.xml.soap:saaj-api:1.3")
|
||||
provided("javax.activation:activation:1.1")
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
optional("commons-io:commons-io:1.3")
|
||||
optional("commons-httpclient:commons-httpclient:3.1")
|
||||
optional("org.apache.httpcomponents:httpclient:4.2")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
optional("taglibs:standard:1.1.2")
|
||||
optional("org.eclipse.jetty:jetty-servlet:8.1.5.v20120716") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
}
|
||||
optional("org.eclipse.jetty:jetty-server:8.1.5.v20120716") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
}
|
||||
optional("log4j:log4j:1.2.17")
|
||||
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
|
||||
testCompile("xmlunit:xmlunit:1.2")
|
||||
}
|
||||
|
||||
// pick up ContextLoader.properties in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
}
|
||||
|
||||
project("spring-orm") {
|
||||
description = "Spring Object/Relational Mapping"
|
||||
dependencies {
|
||||
compile("aopalliance:aopalliance:1.0")
|
||||
optional("org.hibernate:hibernate-core:3.3.2.GA")
|
||||
optional("org.hibernate:hibernate-annotations:3.4.0.GA")
|
||||
optional("org.hibernate:hibernate-entitymanager:3.4.0.GA")
|
||||
optional("org.apache.openjpa:openjpa:1.1.0")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
|
||||
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
|
||||
optional("toplink.essentials:toplink-essentials:2.0-41b")
|
||||
optional("javax.jdo:jdo-api:3.0")
|
||||
optional("org.apache.ibatis:ibatis-sqlmap:2.3.4.726")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.servlet:javax.servlet-api:3.0.1")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("commons-dbcp:commons-dbcp:1.2.2")
|
||||
testCompile("org.eclipse.persistence:org.eclipse.persistence.asm:1.0.1")
|
||||
testCompile("org.eclipse.persistence:org.eclipse.persistence.antlr:1.0.1")
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
testCompile(project(":spring-web").sourceSets.test.output)
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
optional(project(":spring-aop"))
|
||||
optional(project(":spring-context"))
|
||||
compile(project(":spring-tx"))
|
||||
compile(project(":spring-jdbc"))
|
||||
optional(project(":spring-web"))
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-orm-hibernate4") {
|
||||
description = "Spring Object/Relational Mapping - Hibernate 4 support"
|
||||
merge.into = project(":spring-orm")
|
||||
dependencies {
|
||||
compile(project(":spring-tx"))
|
||||
compile(project(":spring-jdbc"))
|
||||
optional("org.hibernate:hibernate-core:4.1.0.Final")
|
||||
optional("org.hibernate:hibernate-entitymanager:4.1.0.Final")
|
||||
optional(project(":spring-web"))
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-webmvc") {
|
||||
description = "Spring Web MVC"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-expression"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-context"))
|
||||
optional(project(":spring-context-support")) // for Velocity support
|
||||
optional(project(":spring-oxm")) // for MarshallingView
|
||||
optional("org.apache.tiles:tiles-api:2.1.2")
|
||||
optional("org.apache.tiles:tiles-core:2.1.2")
|
||||
optional("org.apache.tiles:tiles-jsp:2.1.2")
|
||||
optional("org.apache.tiles:tiles-servlet:2.1.2")
|
||||
optional("velocity-tools:velocity-tools-view:1.4")
|
||||
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
|
||||
optional("org.apache.poi:poi:3.0.2-FINAL")
|
||||
optional("com.lowagie:itext:2.1.7")
|
||||
optional("jasperreports:jasperreports:2.0.5") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
optional("rome:rome:1.0")
|
||||
optional("velocity:velocity:1.5")
|
||||
optional("org.freemarker:freemarker:2.3.15")
|
||||
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("rhino:js:1.7R1")
|
||||
testCompile("xmlunit:xmlunit:1.2")
|
||||
testCompile("dom4j:dom4j:1.6.1") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
}
|
||||
testCompile("jaxen:jaxen:1.1.1") {
|
||||
exclude group: "xml-apis", module: "xml-apis"
|
||||
exclude group: "xom", module: "xom"
|
||||
exclude group: "xerces", module: "xercesImpl"
|
||||
}
|
||||
testCompile("org.eclipse.jetty:jetty-servlet:8.1.5.v20120716") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
}
|
||||
testCompile("org.eclipse.jetty:jetty-server:8.1.5.v20120716") {
|
||||
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
|
||||
}
|
||||
testCompile("javax.validation:validation-api:1.0.0.GA")
|
||||
testCompile("commons-fileupload:commons-fileupload:1.2")
|
||||
testCompile("commons-io:commons-io:1.3")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.apache.httpcomponents:httpclient:4.2")
|
||||
testCompile(project(":spring-web").sourceSets.test.output)
|
||||
}
|
||||
|
||||
// pick up DispatcherServlet.properties in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
}
|
||||
|
||||
project("spring-webmvc-tiles3") {
|
||||
description = "Spring Framework Tiles3 Integration"
|
||||
merge.into = project(":spring-webmvc")
|
||||
dependencies {
|
||||
compile(project(":spring-context"))
|
||||
provided("javax.el:el-api:1.0")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
provided("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
optional("org.apache.tiles:tiles-api:3.0.1")
|
||||
optional("org.apache.tiles:tiles-core:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-servlet:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-jsp:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
optional("org.apache.tiles:tiles-el:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
compile(project(":spring-web").sourceSets*.output) // mock request & response
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-webmvc-portlet") {
|
||||
description = "Spring Web Portlet"
|
||||
dependencies {
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.portlet:portlet-api:2.0")
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-webmvc"))
|
||||
optional("commons-fileupload:commons-fileupload:1.2")
|
||||
}
|
||||
|
||||
// pick up DispatcherPortlet.properties in src/main
|
||||
sourceSets.main.resources.srcDirs += "src/main/java"
|
||||
}
|
||||
|
||||
project("spring-test") {
|
||||
description = "Spring TestContext Framework"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
optional(project(":spring-beans"))
|
||||
optional(project(":spring-context"))
|
||||
optional(project(":spring-jdbc"))
|
||||
optional(project(":spring-tx"))
|
||||
optional(project(":spring-orm"))
|
||||
optional(project(":spring-web"))
|
||||
optional(project(":spring-webmvc"))
|
||||
optional(project(":spring-webmvc-portlet"), )
|
||||
optional("junit:junit:${junitVersion}")
|
||||
optional("org.testng:testng:6.5.2")
|
||||
optional("javax.servlet:servlet-api:2.5")
|
||||
optional("javax.servlet.jsp:jsp-api:2.1")
|
||||
optional("javax.portlet:portlet-api:2.0")
|
||||
optional("javax.persistence:persistence-api:1.0")
|
||||
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("org.hibernate:hibernate-core:3.3.2.GA")
|
||||
provided("javax.inject:javax.inject:1")
|
||||
provided("javax.activation:activation:1.1")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-test-mvc") {
|
||||
description = "Spring Test MVC Framework"
|
||||
merge.into = project(":spring-test")
|
||||
dependencies {
|
||||
optional(project(":spring-context"))
|
||||
compile(project(":spring-webmvc"))
|
||||
provided("javax.servlet:javax.servlet-api:3.0.1")
|
||||
optional("org.hamcrest:hamcrest-core:1.3")
|
||||
optional("com.jayway.jsonpath:json-path:0.8.1")
|
||||
optional("xmlunit:xmlunit:1.2")
|
||||
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
|
||||
testCompile("javax.servlet:jstl:1.2")
|
||||
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
|
||||
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
|
||||
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.1")
|
||||
testCompile(project(":spring-context-support"))
|
||||
testCompile(project(":spring-oxm"))
|
||||
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
|
||||
testCompile("cglib:cglib-nodep:2.2")
|
||||
testCompile("rome:rome:1.0")
|
||||
testCompile("javax.activation:activation:1.1")
|
||||
testCompile("javax.mail:mail:1.4")
|
||||
testCompile("javax.xml.bind:jaxb-api:2.2.6")
|
||||
testCompile("org.easymock:easymockclassextension:${easymockVersion}")
|
||||
testCompile("org.apache.tiles:tiles-request-api:1.0.1")
|
||||
testCompile("org.apache.tiles:tiles-api:3.0.1")
|
||||
testCompile("org.apache.tiles:tiles-core:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
testCompile("org.apache.tiles:tiles-servlet:3.0.1") {
|
||||
exclude group: "org.slf4j", module: "jcl-over-slf4j"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-struts") {
|
||||
description = "Spring Struts"
|
||||
dependencies {
|
||||
compile(project(":spring-core"))
|
||||
compile(project(":spring-beans"))
|
||||
compile(project(":spring-context"))
|
||||
compile(project(":spring-web"))
|
||||
compile(project(":spring-webmvc"))
|
||||
compile("struts:struts:1.2.9")
|
||||
compile("commons-beanutils:commons-beanutils:1.7.0")
|
||||
provided("javax.servlet:servlet-api:2.5")
|
||||
provided("javax.servlet:jstl:1.2")
|
||||
testCompile(project(":spring-test"))
|
||||
}
|
||||
}
|
||||
|
||||
project("spring-aspects") {
|
||||
description = "Spring Aspects"
|
||||
apply from: "aspects.gradle"
|
||||
dependencies {
|
||||
optional(project(":spring-beans")) // for @Configurable support
|
||||
optional(project(":spring-aop")) // for @Async support
|
||||
optional(project(":spring-context")) // for @Enable* support
|
||||
compile(project(":spring-context-support")) // for JavaMail support
|
||||
optional(project(":spring-tx")) // for JPA, @Transactional support
|
||||
optional(project(":spring-orm")) // for JPA exception translation support
|
||||
aspects(project(":spring-orm"))
|
||||
provided("javax.persistence:persistence-api:1.0")
|
||||
testCompile("javax.mail:mail:1.4")
|
||||
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
|
||||
rt("org.aspectj:aspectjrt:${aspectjVersion}")
|
||||
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile(project(":spring-core")) // for CodeStyleAspect
|
||||
compile(project(":spring-beans")) // for "p" namespace visibility
|
||||
testCompile(project(":spring-test"))
|
||||
}
|
||||
eclipse.project {
|
||||
natures += "org.eclipse.ajdt.ui.ajnature"
|
||||
buildCommands = [new org.gradle.plugins.ide.eclipse.model.
|
||||
BuildCommand("org.eclipse.ajdt.core.ajbuilder")]
|
||||
}
|
||||
}
|
||||
|
||||
configure(rootProject) {
|
||||
description = "Spring Framework"
|
||||
|
||||
apply plugin: "docbook-reference"
|
||||
apply plugin: "groovy"
|
||||
apply from: "${gradleScriptDir}/jdiff.gradle"
|
||||
|
||||
reference {
|
||||
sourceDir = file("src/reference/docbook")
|
||||
pdfFilename = "spring-framework-reference.pdf"
|
||||
}
|
||||
|
||||
// don"t publish the default jar for the root project
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
dependencies { // for integration tests
|
||||
testCompile(project(":spring-core"))
|
||||
testCompile(project(":spring-beans"))
|
||||
testCompile(project(":spring-aop"))
|
||||
testCompile(project(":spring-expression"))
|
||||
testCompile(project(":spring-context"))
|
||||
testCompile(project(":spring-tx"))
|
||||
testCompile(project(":spring-jdbc"))
|
||||
testCompile(project(":spring-test"))
|
||||
testCompile(project(":spring-web"))
|
||||
testCompile(project(":spring-webmvc-portlet"))
|
||||
testCompile(project(":spring-orm"))
|
||||
testCompile("org.hibernate:hibernate-core:4.1.0.Final")
|
||||
testCompile("javax.servlet:servlet-api:2.5")
|
||||
testCompile("javax.portlet:portlet-api:2.0")
|
||||
testCompile("javax.inject:javax.inject:1")
|
||||
testCompile("javax.resource:connector-api:1.5")
|
||||
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
|
||||
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
|
||||
}
|
||||
|
||||
task api(type: Javadoc) {
|
||||
group = "Documentation"
|
||||
description = "Generates aggregated Javadoc API documentation."
|
||||
title = "${rootProject.description} ${version} API"
|
||||
|
||||
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
|
||||
options.author = true
|
||||
options.header = rootProject.description
|
||||
options.overview = "src/api/overview.html"
|
||||
options.splitIndex = true
|
||||
options.links(project.ext.javadocLinks)
|
||||
|
||||
source subprojects.collect { project ->
|
||||
project.sourceSets.main.allJava
|
||||
}
|
||||
|
||||
classpath = files(
|
||||
// ensure servlet 3.x and Hibernate 4.x have precedence on the Javadoc
|
||||
// classpath over their respective 2.5 and 3.x variants
|
||||
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
|
||||
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
|
||||
// ensure the javadoc process can resolve types compiled from .aj sources
|
||||
project(":spring-aspects").sourceSets.main.output
|
||||
)
|
||||
classpath += files(subprojects.collect { it.sourceSets.main.compileClasspath })
|
||||
|
||||
maxMemory = "1024m"
|
||||
destinationDir = new File(buildDir, "api")
|
||||
}
|
||||
|
||||
task docsZip(type: Zip) {
|
||||
group = "Distribution"
|
||||
baseName = "spring-framework"
|
||||
classifier = "docs"
|
||||
description = "Builds -${classifier} archive containing api and reference " +
|
||||
"for deployment at http://static.springframework.org/spring-framework/docs."
|
||||
|
||||
from("src/dist") {
|
||||
include "changelog.txt"
|
||||
}
|
||||
|
||||
from (api) {
|
||||
into "javadoc-api"
|
||||
}
|
||||
|
||||
from (reference) {
|
||||
into "spring-framework-reference"
|
||||
}
|
||||
}
|
||||
|
||||
task schemaZip(type: Zip) {
|
||||
group = "Distribution"
|
||||
baseName = "spring-framework"
|
||||
classifier = "schema"
|
||||
description = "Builds -${classifier} archive containing all " +
|
||||
"XSDs for deployment at http://springframework.org/schema."
|
||||
|
||||
subprojects.each { subproject ->
|
||||
def Properties schemas = new Properties();
|
||||
|
||||
subproject.sourceSets.main.resources.find {
|
||||
it.path.endsWith("META-INF/spring.schemas")
|
||||
}?.withInputStream { schemas.load(it) }
|
||||
|
||||
for (def key : schemas.keySet()) {
|
||||
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
|
||||
assert shortName != key
|
||||
File xsdFile = subproject.sourceSets.main.resources.find {
|
||||
it.path.endsWith(schemas.get(key))
|
||||
}
|
||||
assert xsdFile != null
|
||||
into (shortName) {
|
||||
from xsdFile.path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) {
|
||||
group = "Distribution"
|
||||
baseName = "spring-framework"
|
||||
classifier = "dist"
|
||||
description = "Builds -${classifier} archive, containing all jars and docs, " +
|
||||
"suitable for community download page."
|
||||
|
||||
ext.baseDir = "${baseName}-${project.version}";
|
||||
|
||||
from("src/dist") {
|
||||
include "readme.txt"
|
||||
include "license.txt"
|
||||
include "notice.txt"
|
||||
into "${baseDir}"
|
||||
expand(copyright: new Date().format("yyyy"), version: project.version)
|
||||
}
|
||||
|
||||
from(zipTree(docsZip.archivePath)) {
|
||||
into "${baseDir}/docs"
|
||||
}
|
||||
|
||||
from(zipTree(schemaZip.archivePath)) {
|
||||
into "${baseDir}/schema"
|
||||
}
|
||||
|
||||
subprojects.each { subproject ->
|
||||
into ("${baseDir}/libs") {
|
||||
from subproject.jar
|
||||
if (subproject.tasks.findByPath("sourcesJar")) {
|
||||
from subproject.sourcesJar
|
||||
}
|
||||
if (subproject.tasks.findByPath("javadocJar")) {
|
||||
from subproject.javadocJar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an distribution that contains all dependencies (required and optional).
|
||||
// Not published by default; only for use when building from source.
|
||||
task depsZip(type: Zip, dependsOn: distZip) { zipTask ->
|
||||
group = "Distribution"
|
||||
baseName = "spring-framework"
|
||||
classifier = "dist-with-deps"
|
||||
description = "Builds -${classifier} archive, containing everything " +
|
||||
"in the -${distZip.classifier} archive plus all runtime dependencies."
|
||||
|
||||
from zipTree(distZip.archivePath)
|
||||
|
||||
gradle.taskGraph.whenReady { taskGraph ->
|
||||
if (taskGraph.hasTask(":${zipTask.name}")) {
|
||||
def projectNames = rootProject.subprojects*.name
|
||||
def artifacts = new HashSet()
|
||||
subprojects.each { subproject ->
|
||||
(subproject.configurations.runtime.resolvedConfiguration.resolvedArtifacts +
|
||||
subproject.configurations.optional.resolvedConfiguration.resolvedArtifacts).each { artifact ->
|
||||
def dependency = artifact.moduleVersion.id
|
||||
if (!projectNames.contains(dependency.name)) {
|
||||
artifacts << artifact.file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zipTask.from(artifacts) {
|
||||
into "${distZip.baseDir}/deps"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives docsZip
|
||||
archives schemaZip
|
||||
archives distZip
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = "Generates gradlew[.bat] scripts"
|
||||
gradleVersion = "1.3"
|
||||
|
||||
doLast() {
|
||||
def gradleOpts = "-XX:MaxPermSize=1024m -Xmx1024m"
|
||||
def gradleBatOpts = "$gradleOpts -XX:MaxHeapSize=256m"
|
||||
File wrapperFile = file("gradlew")
|
||||
wrapperFile.text = wrapperFile.text.replace("DEFAULT_JVM_OPTS=",
|
||||
"GRADLE_OPTS=\"$gradleOpts \$GRADLE_OPTS\"\nDEFAULT_JVM_OPTS=")
|
||||
File wrapperBatFile = file("gradlew.bat")
|
||||
wrapperBatFile.text = wrapperBatFile.text.replace("set DEFAULT_JVM_OPTS=",
|
||||
"set GRADLE_OPTS=$gradleBatOpts %GRADLE_OPTS%\nset DEFAULT_JVM_OPTS=")
|
||||
}
|
||||
}
|
||||
node {
|
||||
version = '24.15.0'
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.build.gradle.merge
|
||||
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
import org.gradle.api.artifacts.maven.Conf2ScopeMapping
|
||||
import org.gradle.api.plugins.MavenPlugin
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.plugins.ide.eclipse.EclipsePlugin
|
||||
import org.gradle.plugins.ide.eclipse.model.EclipseClasspath;
|
||||
import org.gradle.plugins.ide.idea.IdeaPlugin
|
||||
import org.gradle.api.invocation.*
|
||||
|
||||
|
||||
/**
|
||||
* Gradle plugin that allows projects to merged together. Primarily developed to
|
||||
* allow Spring to support multiple multiple incompatible versions of third-party
|
||||
* dependencies (for example Hibernate v3 and v4).
|
||||
* <p>
|
||||
* The 'merge' extension should be used to define how projects are merged, for example:
|
||||
* <pre>
|
||||
* configure(subprojects) {
|
||||
* apply plugin: MergePlugin
|
||||
* }
|
||||
*
|
||||
* project("myproject") {
|
||||
* }
|
||||
*
|
||||
* project("myproject-extra") {
|
||||
* merge.into = project("myproject")
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* This plugin adds two new configurations:
|
||||
* <ul>
|
||||
* <li>merging - Contains the projects being merged into this project<li>
|
||||
* <li>runtimeMerge - Contains all dependencies that are merge projects. These are used
|
||||
* to allow an IDE to reference merge projects.</li>
|
||||
* <ul>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MergePlugin implements Plugin<Project> {
|
||||
|
||||
private static boolean attachedProjectsEvaluated;
|
||||
|
||||
public void apply(Project project) {
|
||||
project.plugins.apply(MavenPlugin)
|
||||
project.plugins.apply(EclipsePlugin)
|
||||
project.plugins.apply(IdeaPlugin)
|
||||
|
||||
MergeModel model = project.extensions.create("merge", MergeModel)
|
||||
project.configurations.add("merging")
|
||||
Configuration runtimeMerge = project.configurations.add("runtimeMerge")
|
||||
|
||||
// Ensure the IDE can reference merged projects
|
||||
project.eclipse.classpath.plusConfigurations += [runtimeMerge]
|
||||
project.idea.module.scopes.PROVIDED.plus += runtimeMerge
|
||||
|
||||
// Hook to perform the actual merge logic
|
||||
project.afterEvaluate{
|
||||
if(it.merge.into != null) {
|
||||
setup(it)
|
||||
}
|
||||
}
|
||||
|
||||
// Hook to build runtimeMerge dependencies
|
||||
if(!attachedProjectsEvaluated) {
|
||||
project.gradle.projectsEvaluated{
|
||||
postProcessProjects(it)
|
||||
}
|
||||
attachedProjectsEvaluated = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void setup(Project project) {
|
||||
project.merge.into.dependencies.add("merging", project)
|
||||
project.dependencies.add("provided", project.merge.into.sourceSets.main.output)
|
||||
project.dependencies.add("runtimeMerge", project.merge.into)
|
||||
setupTaskDependencies(project)
|
||||
setupMaven(project)
|
||||
}
|
||||
|
||||
private void setupTaskDependencies(Project project) {
|
||||
// invoking a task will invoke the task with the same name on 'into' project
|
||||
["sourcesJar", "jar", "javadocJar", "javadoc", "install", "artifactoryPublish"].each {
|
||||
def task = project.tasks.findByPath(it)
|
||||
if(task) {
|
||||
task.enabled = false
|
||||
task.dependsOn(project.merge.into.tasks.findByPath(it))
|
||||
}
|
||||
}
|
||||
|
||||
// update 'into' project artifacts to contain the source artifact contents
|
||||
project.merge.into.sourcesJar.from(project.sourcesJar.source)
|
||||
project.merge.into.jar.from(project.jar.source)
|
||||
project.merge.into.javadoc {
|
||||
source += project.javadoc.source
|
||||
classpath += project.javadoc.classpath
|
||||
}
|
||||
}
|
||||
|
||||
private void setupMaven(Project project) {
|
||||
project.configurations.each { configuration ->
|
||||
Conf2ScopeMapping mapping = project.conf2ScopeMappings.getMapping([configuration])
|
||||
if(mapping.scope) {
|
||||
Configuration intoConfiguration = project.merge.into.configurations.add(
|
||||
project.name + "-" + configuration.name)
|
||||
configuration.excludeRules.each {
|
||||
configuration.exclude([
|
||||
(ExcludeRule.GROUP_KEY) : it.group,
|
||||
(ExcludeRule.MODULE_KEY) : it.module])
|
||||
}
|
||||
intoConfiguration.dependencies.addAll(configuration.dependencies)
|
||||
project.merge.into.install.repositories.mavenInstaller.pom.scopeMappings.addMapping(
|
||||
mapping.priority + 100, intoConfiguration, mapping.scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private postProcessProjects(Gradle gradle) {
|
||||
gradle.allprojects(new Action<Project>() {
|
||||
public void execute(Project project) {
|
||||
project.configurations.getByName("runtime").allDependencies.withType(ProjectDependency).each{
|
||||
Configuration dependsOnMergedFrom = it.dependencyProject.configurations.getByName("merging");
|
||||
dependsOnMergedFrom.dependencies.each{ dep ->
|
||||
project.dependencies.add("runtimeMerge", dep.dependencyProject)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class MergeModel {
|
||||
Project into;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
implementation-class=org.springframework.build.gradle.merge.MergePlugin
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
version=3.2.0.RELEASE
|
||||
group=org.springframework
|
||||
description=Spring Framework Docs Site
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import org.gradle.plugins.ide.eclipse.model.ProjectDependency
|
||||
|
||||
eclipse.classpath.file.whenMerged { classpath ->
|
||||
// GRADLE-1116
|
||||
def regexp = /.*?\/([^\/]+)\/build\/[^\/]+\/(?:main|test)/ // only match those that end in main or test (avoids removing necessary entries like build/classes/jaxb)
|
||||
def projectOutputDependencies = classpath.entries.findAll { entry -> entry.path =~ regexp }
|
||||
projectOutputDependencies.each { entry ->
|
||||
def matcher = (entry.path =~ regexp)
|
||||
if(matcher) {
|
||||
def projectName = matcher[0][1]
|
||||
def path = "/${projectName}"
|
||||
if(!classpath.entries.find { e -> e instanceof ProjectDependency && e.path == path }) {
|
||||
def dependency = new ProjectDependency(path, project(":${projectName}").path)
|
||||
dependency.exported = true
|
||||
classpath.entries.add(dependency)
|
||||
}
|
||||
classpath.entries.remove(entry)
|
||||
}
|
||||
}
|
||||
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Generate a JDiff report between the current version and an older version.
|
||||
*
|
||||
* Usage:
|
||||
* gradle jdiff -D OLD_VERSION=3.1.3.RELEASE -D OLD_VERSION_ROOT=/path/to/3.1.3.RELEASE
|
||||
*
|
||||
* View generated report at:
|
||||
* build/reports/jdiff/changes.html
|
||||
*
|
||||
* @param OLD_VERSION required
|
||||
* @param OLD_VERSION_ROOT required, typically pointing to a separate git clone dir
|
||||
*/
|
||||
task jdiff {
|
||||
description = "Generates a JDiff report"
|
||||
group = "Documentation"
|
||||
|
||||
def jdiffHome = "${rootProject.rootDir}/gradle/jdiff"
|
||||
|
||||
ant.taskdef(
|
||||
name: "jdiff",
|
||||
classname: "jdiff.JDiffAntTask",
|
||||
classpath: "${jdiffHome}/antjdiff.jar")
|
||||
|
||||
def currentVersion = rootProject.version
|
||||
def currentVersionRoot = rootProject.rootDir
|
||||
|
||||
def oldVersion = System.getProperty("OLD_VERSION")
|
||||
def oldVersionRoot = System.getProperty("OLD_VERSION_ROOT")
|
||||
|
||||
def outputDir = "${rootProject.buildDir}/reports/jdiff/${oldVersion}_to_${currentVersion}"
|
||||
|
||||
doLast {
|
||||
if (oldVersion == null)
|
||||
throw new IllegalArgumentException(
|
||||
"Set OLD_VERSION property to indicate older of the two versions being compared")
|
||||
if (oldVersionRoot == null)
|
||||
throw new IllegalArgumentException(
|
||||
"Set OLD_VERSION_ROOT property to indicate the root directory for ${oldVersion}")
|
||||
|
||||
oldVersionRoot = new File(oldVersionRoot)
|
||||
|
||||
ant.property(name: "JDIFF_HOME", value: jdiffHome)
|
||||
ant.mkdir(dir: outputDir)
|
||||
ant.jdiff(
|
||||
destdir: outputDir,
|
||||
verbose: "off",
|
||||
stats: "on",
|
||||
docchanges: "on") {
|
||||
old(name: "Spring Framework ${oldVersion}") {
|
||||
oldVersionRoot.eachDirMatch( {
|
||||
def candidate = new File(it)
|
||||
candidate.name.matches("org.springframework.*") ||
|
||||
candidate.name.matches("spring-.*") }) { match ->
|
||||
match.eachDirRecurse { subdir ->
|
||||
if (subdir.path ==~ '.*/src/main/java$') {
|
||||
dirset(dir: subdir.path, includes: "org/**")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"new"(name: "Spring Framework ${currentVersion}") {
|
||||
currentVersionRoot.eachDirMatch( {
|
||||
def candidate = new File(it)
|
||||
candidate.name.matches("org.springframework.*") ||
|
||||
candidate.name.matches("spring-.*") }) { match ->
|
||||
match.eachDirRecurse { subdir ->
|
||||
if (subdir.path ==~ '.*/src/main/java$') {
|
||||
dirset(dir: subdir.path, includes: "org/**")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,506 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* This class is used only as a "null" argument for Javadoc when comparing
|
||||
* two API files. Javadoc has to have a package, .java or .class file as an
|
||||
* argument, even though JDiff doesn't use it.
|
||||
*/
|
||||
public class Null {
|
||||
public Null() {
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
This distribution of JDiff 1.1.1 is included in the Spring Framework build
|
||||
because JDiff has a hard requirement on a JDIFF_HOME directory containing
|
||||
jdiff.jar and xerces.jar as well as other presentation resources.
|
||||
|
||||
The actual generation of JDiff reports is driven by the `jdiff` task declared
|
||||
in build.gradle in the project root.
|
||||
@@ -1,59 +0,0 @@
|
||||
|
||||
JDiff Doclet
|
||||
------------
|
||||
|
||||
Matthew Doar
|
||||
mdoar@pobox.com
|
||||
|
||||
|
||||
The JDiff doclet is used to generate a report describing the
|
||||
difference between two public Java APIs.
|
||||
|
||||
The file jdiff.html contains the reference page for JDiff. The latest
|
||||
version of JDiff can be downloaded at:
|
||||
http://sourceforge.net/projects/javadiff
|
||||
|
||||
To use the Ant task on your own project, see example.xml. More examples
|
||||
of using JDiff to compare the public APIs of J2SE1.3 and J2SE1.4 can
|
||||
be seen at http://www.jdiff.org
|
||||
|
||||
For an example with the source distribution, run "ant" and
|
||||
look at the HTML output in ./build/reports/example/changes.html
|
||||
The page at ./build/reports/example/changes/com.acme.sp.SPImpl.html
|
||||
shows what a typical page of changes looks like.
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
|
||||
JDiff has been tested with all releases of Java since J2SE1.2 but
|
||||
releases of JDiff after 1.10.0 focus on JDK1.5.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
JDiff is licensed under the Lesser GNU General Public License (LGPL).
|
||||
See the file LICENSE.txt.
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
JDiff uses Stuart D. Gathman's Java translation of Gene Myers' O(ND)
|
||||
difference algorithm.
|
||||
|
||||
JDiff uses Xerces 1.4.2 from http://www.apache.org.
|
||||
|
||||
JDiff also includes a script to use the classdoc application from
|
||||
http://classdoc.sourceforge.net or http://www.jensgulden.de, by Jens
|
||||
Gulden, (mail@jensgulden.de), to call a doclet such as jdiff on a .jar
|
||||
file rather than on source.
|
||||
|
||||
Many thanks to the reviewers at Sun and Vitria who gave feedback on early
|
||||
versions of JDiff output, and also to the distillers of Laphroaig, and to
|
||||
Arturo Fuente for his consistently fine cigars which helped inspire
|
||||
much of this work.
|
||||
|
||||
|
||||
Footnote:
|
||||
|
||||
If you are looking for a generalized diff tool for XML, try diffmk from
|
||||
http://wwws.sun.com/software/xml/developers/diffmk/
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 559 B |
Binary file not shown.
|
Before Width: | Height: | Size: 799 B |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 116 B |
Binary file not shown.
@@ -1,46 +0,0 @@
|
||||
apply plugin: "propdeps-maven"
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
customizePom(pom, project)
|
||||
}
|
||||
}
|
||||
|
||||
def customizePom(pom, gradleProject) {
|
||||
pom.whenConfigured { generatedPom ->
|
||||
// eliminate test-scoped dependencies (no need in maven central poms)
|
||||
generatedPom.dependencies.removeAll { dep ->
|
||||
dep.scope == "test"
|
||||
}
|
||||
|
||||
// add all items necessary for maven central publication
|
||||
generatedPom.project {
|
||||
name = gradleProject.description
|
||||
description = gradleProject.description
|
||||
url = "https://github.com/SpringSource/spring-framework"
|
||||
organization {
|
||||
name = "SpringSource"
|
||||
url = "http://springsource.org/spring-framework"
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name "The Apache Software License, Version 2.0"
|
||||
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
distribution "repo"
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = "https://github.com/SpringSource/spring-framework"
|
||||
connection = "scm:git:git://github.com/SpringSource/spring-framework"
|
||||
developerConnection = "scm:git:git://github.com/SpringSource/spring-framework"
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = "jhoeller"
|
||||
name = "Juergen Hoeller"
|
||||
email = "jhoeller@vmware.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
+3
-2
@@ -1,6 +1,7 @@
|
||||
#Wed Nov 28 09:14:59 PST 2012
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip
|
||||
|
||||
@@ -1,80 +1,129 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
GRADLE_OPTS="-XX:MaxPermSize=1024m -Xmx1024m $GRADLE_OPTS"
|
||||
DEFAULT_JVM_OPTS=""
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn ( ) {
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die ( ) {
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -83,83 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
Vendored
+47
-44
@@ -1,4 +1,22 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -8,27 +26,30 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set GRADLE_OPTS=-XX:MaxPermSize=1024m -Xmx1024m -XX:MaxHeapSize=256m %GRADLE_OPTS%
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -36,54 +57,36 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
@echo off
|
||||
set STS_TEST_VERSION='2.9.2.RELEASE'
|
||||
|
||||
set CURRENT_DIR=%~dp0
|
||||
cd %CURRENT_DIR%
|
||||
|
||||
cls
|
||||
|
||||
echo.
|
||||
echo -----------------------------------------------------------------------
|
||||
echo Spring Framework Eclipse/STS project import guide
|
||||
echo.
|
||||
echo This script will guide you through the process of importing the
|
||||
echo Spring Framework sources into Eclipse/STS. It is recommended that you
|
||||
echo have a recent version of the SpringSource Tool Suite (this script has
|
||||
echo been tested against STS %STS_TEST_VERSION%), but at the minimum you will
|
||||
echo need Eclipse + AJDT.
|
||||
echo.
|
||||
echo If you need to download and install STS, please do that now by
|
||||
echo visiting http://springsource.org/downloads/sts
|
||||
echo.
|
||||
echo Otherwise, press enter and we'll begin.
|
||||
|
||||
pause
|
||||
|
||||
REM this command:
|
||||
REM - wipes out any existing Eclipse metadata
|
||||
REM - generates OXM test classes to avoid errors on import into Eclipse
|
||||
REM - generates metadata for all subprojects
|
||||
REM - skips metadata gen for the root project (-x :eclipse) to work
|
||||
REM around Eclipse's inability to import hierarchical project structures
|
||||
REM SET COMMAND="./gradlew cleanEclipse :spring-oxm:compileTestJava eclipse -x :eclipse"
|
||||
SET COMMAND=gradlew cleanEclipse :spring-oxm:compileTestJava eclipse -x :eclipse
|
||||
|
||||
echo.
|
||||
echo -----------------------------------------------------------------------
|
||||
echo STEP 1: Generate subproject Eclipse metadata
|
||||
echo.
|
||||
echo The first step will be to generate Eclipse project metadata for each
|
||||
echo of the spring-* subprojects. This happens via the built-in
|
||||
echo "Gradle wrapper" script (./gradlew in this directory). If this is your
|
||||
echo first time using the Gradle wrapper, this step may take a few minutes
|
||||
echo while a Gradle distribution is downloaded for you.
|
||||
echo.
|
||||
echo The command run will be:
|
||||
echo.
|
||||
echo %COMMAND%
|
||||
echo.
|
||||
echo Press enter when ready.
|
||||
|
||||
pause
|
||||
|
||||
call %COMMAND%
|
||||
if not "%ERRORLEVEL%" == "0" exit /B %ERRORLEVEL%
|
||||
|
||||
echo.
|
||||
echo -----------------------------------------------------------------------
|
||||
echo STEP 2: Import subprojects into Eclipse/STS
|
||||
echo.
|
||||
echo Within Eclipse/STS, do the following:
|
||||
echo.
|
||||
echo File ^> Import... ^> Existing Projects into Workspace
|
||||
echo ^> When prompted for the 'root directory', provide %CURRENT_DIR%
|
||||
echo ^> Press enter. You will see the modules show up under "Projects"
|
||||
echo ^> All projects should be selected/checked. Click Finish.
|
||||
echo ^> When the project import is complete, you should have no errors.
|
||||
echo.
|
||||
echo When the above is complete, return here and press the enter key.
|
||||
|
||||
pause
|
||||
|
||||
set COMMAND=gradlew :eclipse
|
||||
|
||||
echo.
|
||||
echo -----------------------------------------------------------------------
|
||||
echo STEP 3: generate root project Eclipse metadata
|
||||
echo.
|
||||
echo Unfortunately, Eclipse does not allow for importing project
|
||||
echo hierarchies, so we had to skip root project metadata generation in the
|
||||
echo during step 1. In this step we simply generate root project metadata
|
||||
echo so you can import it in the next step.
|
||||
echo.
|
||||
echo The command run will be:
|
||||
echo.
|
||||
echo %COMMAND%
|
||||
echo.
|
||||
echo Press the enter key when ready.
|
||||
pause
|
||||
|
||||
call %COMMAND%
|
||||
if not "%ERRORLEVEL%" == "0" exit /B %ERRORLEVEL%
|
||||
|
||||
echo.
|
||||
echo -----------------------------------------------------------------------
|
||||
echo STEP 4: Import root project into Eclipse/STS
|
||||
echo.
|
||||
echo Follow the project import steps listed in step 2 above to import the
|
||||
echo root project.
|
||||
echo.
|
||||
echo Press enter when complete, and move on to the final step.
|
||||
|
||||
pause
|
||||
|
||||
echo.
|
||||
echo -----------------------------------------------------------------------
|
||||
echo STEP 5: Enable Git support for all projects
|
||||
echo.
|
||||
echo - In the Eclipse/STS Package Explorer, select all spring* projects.
|
||||
echo - Right-click to open the context menu and select Team ^> Share Project...
|
||||
echo - In the Share Project dialog that appears, select Git and press Next
|
||||
echo - Check "Use or create repository in parent folder of project"
|
||||
echo - Click Finish
|
||||
echo.
|
||||
echo When complete, you'll have Git support enabled for all projects.
|
||||
echo.
|
||||
echo You're ready to code! Goodbye!
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
STS_TEST_VERSION='2.9.2.RELEASE'
|
||||
|
||||
cd `dirname $0`
|
||||
clear
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Spring Framework Eclipse/STS project import guide
|
||||
|
||||
This script will guide you through the process of importing the
|
||||
Spring Framework sources into Eclipse/STS. It is recommended that you
|
||||
have a recent version of the SpringSource Tool Suite (this script has
|
||||
been tested against STS $STS_TEST_VERSION), but at the minimum you will
|
||||
need Eclipse + AJDT.
|
||||
|
||||
If you need to download and install STS, please do that now by
|
||||
visiting http://springsource.org/downloads/sts
|
||||
|
||||
Otherwise, press enter and we'll begin.
|
||||
EOM
|
||||
|
||||
read
|
||||
|
||||
# this command:
|
||||
# - wipes out any existing Eclipse metadata
|
||||
# - generates OXM test classes to avoid errors on import into Eclipse
|
||||
# - generates metadata for all subprojects
|
||||
# - skips metadata gen for the root project (-x :eclipse) to work
|
||||
# around Eclipse's inability to import hierarchical project structures
|
||||
COMMAND="./gradlew cleanEclipse :spring-oxm:compileTestJava eclipse -x :eclipse"
|
||||
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
STEP 1: Generate subproject Eclipse metadata
|
||||
|
||||
The first step will be to generate Eclipse project metadata for each
|
||||
of the spring-* subprojects. This happens via the built-in
|
||||
"Gradle wrapper" script (./gradlew in this directory). If this is your
|
||||
first time using the Gradle wrapper, this step may take a few minutes
|
||||
while a Gradle distribution is downloaded for you.
|
||||
|
||||
The command run will be:
|
||||
|
||||
$COMMAND
|
||||
|
||||
Press enter when ready.
|
||||
EOM
|
||||
|
||||
read
|
||||
|
||||
$COMMAND || exit
|
||||
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
STEP 2: Import subprojects into Eclipse/STS
|
||||
|
||||
Within Eclipse/STS, do the following:
|
||||
|
||||
File > Import... > Existing Projects into Workspace
|
||||
> When prompted for the 'root directory', provide $PWD
|
||||
> Press enter. You will see the modules show up under "Projects"
|
||||
> All projects should be selected/checked. Click Finish.
|
||||
> When the project import is complete, you should have no errors.
|
||||
|
||||
When the above is complete, return here and press the enter key.
|
||||
EOM
|
||||
|
||||
read
|
||||
|
||||
COMMAND="./gradlew :eclipse"
|
||||
|
||||
cat <<EOM
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
STEP 3: generate root project Eclipse metadata
|
||||
|
||||
Unfortunately, Eclipse does not allow for importing project
|
||||
hierarchies, so we had to skip root project metadata generation in the
|
||||
during step 1. In this step we simply generate root project metadata
|
||||
so you can import it in the next step.
|
||||
|
||||
The command run will be:
|
||||
|
||||
$COMMAND
|
||||
|
||||
Press the enter key when ready.
|
||||
EOM
|
||||
|
||||
read
|
||||
|
||||
$COMMAND || exit
|
||||
|
||||
cat <<EOM
|
||||
-----------------------------------------------------------------------
|
||||
STEP 4: Import root project into Eclipse/STS
|
||||
|
||||
Follow the project import steps listed in step 2 above to import the
|
||||
root project.
|
||||
|
||||
Press enter when complete, and move on to the final step.
|
||||
EOM
|
||||
|
||||
read
|
||||
|
||||
cat <<EOM
|
||||
-----------------------------------------------------------------------
|
||||
STEP 5: Enable Git support for all projects
|
||||
|
||||
- In the Eclipse/STS Package Explorer, select all spring* projects.
|
||||
- Right-click to open the context menu and select Team > Share Project...
|
||||
- In the Share Project dialog that appears, select Git and press Next
|
||||
- Check "Use or create repository in parent folder of project"
|
||||
- Click Finish
|
||||
|
||||
When complete, you'll have Git support enabled for all projects.
|
||||
|
||||
You're ready to code! Goodbye!
|
||||
EOM
|
||||
@@ -1,32 +0,0 @@
|
||||
The following has been tested against Intellij IDEA 11.0.1
|
||||
|
||||
## Steps
|
||||
|
||||
_Within your locally cloned spring-framework working directory:_
|
||||
|
||||
1. Generate IDEA metadata with `./gradlew cleanIdea idea`
|
||||
2. Import into IDEA as usual
|
||||
3. Set the Project JDK as appropriate
|
||||
4. Add git support
|
||||
5. Code away
|
||||
|
||||
## Known issues
|
||||
|
||||
1. MockServletContext and friends will fail to compile in spring-web. To fix this, uncheck the 'export' setting for all servlet-api and tomcat-servlet-api jars. The problem is that spring-web needs Servlet 2.5, but it's picking up Servlet 3.0 from projects that it depends on.
|
||||
2. spring-context will fail to build because there's a duplicate instance of GroovyMessenger in spring-context/src/test/java/org/springframework/scripting/groovy/Messenger.groovy. The solution to this is not known. It's not a problem on Eclipse, because Eclipse doesn't automatically compile .groovy files like IDEA (apparently) does.
|
||||
|
||||
There are no other known problems at this time. Please add to this list, and if you're ambitious, consider playing with the Gradle IDEA generation DSL to fix these problems automatically, e.g.:
|
||||
|
||||
* http://gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaProject.html
|
||||
* http://gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html
|
||||
* http://gradle.org/docs/current/groovydoc/org/gradle/plugins/ide/idea/model/IdeaModule.html
|
||||
|
||||
## Tips
|
||||
|
||||
In any case, please do not check in your own generated .iml, .ipr, or .iws files. You'll notice these files are already intentionally in .gitignore. The same policy goes for eclipse metadata.
|
||||
|
||||
## FAQ
|
||||
|
||||
Q. What about IDEA's own [Gradle support](http://confluence.jetbrains.net/display/IDEADEV/Gradle+integration)?
|
||||
|
||||
A. Unknown. Please report back if you try it and it goes well for you.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"antora": "3.2.0-alpha.12",
|
||||
"@antora/atlas-extension": "1.0.0-alpha.5",
|
||||
"@antora/collector-extension": "1.0.3",
|
||||
"@asciidoctor/tabs": "1.0.0-beta.6",
|
||||
"@springio/antora-extensions": "1.14.12",
|
||||
"fast-xml-parser": "5.7.0",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.18"
|
||||
}
|
||||
}
|
||||
+3
-23
@@ -1,24 +1,4 @@
|
||||
rootProject.name = "spring"
|
||||
plugins {
|
||||
id "org.gradle.toolchains.foojay-resolver-convention" version "1.0.0"
|
||||
}
|
||||
|
||||
include "spring-aop"
|
||||
include "spring-aspects"
|
||||
include "spring-beans"
|
||||
include "spring-context"
|
||||
include "spring-context-support"
|
||||
include "spring-core"
|
||||
include "spring-expression"
|
||||
include "spring-instrument"
|
||||
include "spring-instrument-tomcat"
|
||||
include "spring-jdbc"
|
||||
include "spring-jms"
|
||||
include "spring-orm"
|
||||
include "spring-orm-hibernate4"
|
||||
include "spring-oxm"
|
||||
include "spring-struts"
|
||||
include "spring-test"
|
||||
include "spring-test-mvc"
|
||||
include "spring-tx"
|
||||
include "spring-web"
|
||||
include "spring-webmvc"
|
||||
include "spring-webmvc-portlet"
|
||||
include "spring-webmvc-tiles3"
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
/**
|
||||
* Base interface holding AOP <b>advice</b> (action to take at a joinpoint)
|
||||
* and a filter determining the applicability of the advice (such as
|
||||
* a pointcut). <i>This interface is not for use by Spring users, but to
|
||||
* allow for commonality in support for different types of advice.</i>
|
||||
*
|
||||
* <p>Spring AOP is based around <b>around advice</b> delivered via method
|
||||
* <b>interception</b>, compliant with the AOP Alliance interception API.
|
||||
* The Advisor interface allows support for different types of advice,
|
||||
* such as <b>before</b> and <b>after</b> advice, which need not be
|
||||
* implemented using interception.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public interface Advisor {
|
||||
|
||||
/**
|
||||
* Return the advice part of this aspect. An advice may be an
|
||||
* interceptor, a before advice, a throws advice, etc.
|
||||
* @return the advice that should apply if the pointcut matches
|
||||
* @see org.aopalliance.intercept.MethodInterceptor
|
||||
* @see BeforeAdvice
|
||||
* @see ThrowsAdvice
|
||||
* @see AfterReturningAdvice
|
||||
*/
|
||||
Advice getAdvice();
|
||||
|
||||
/**
|
||||
* Return whether this advice is associated with a particular instance
|
||||
* (for example, creating a mixin) or shared with all instances of
|
||||
* the advised class obtained from the same Spring bean factory.
|
||||
* <p><b>Note that this method is not currently used by the framework.</b>
|
||||
* Typical Advisor implementations always return <code>true</code>.
|
||||
* Use singleton/prototype bean definitions or appropriate programmatic
|
||||
* proxy creation to ensure that Advisors have the correct lifecycle model.
|
||||
* @return whether this advice is associated with a particular target instance
|
||||
*/
|
||||
boolean isPerInstance();
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
/**
|
||||
* Common marker interface for after advice,
|
||||
* such as {@link AfterReturningAdvice} and {@link ThrowsAdvice}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.3
|
||||
* @see BeforeAdvice
|
||||
*/
|
||||
public interface AfterAdvice extends Advice {
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* After returning advice is invoked only on normal method return, not if an
|
||||
* exception is thrown. Such advice can see the return value, but cannot change it.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see MethodBeforeAdvice
|
||||
* @see ThrowsAdvice
|
||||
*/
|
||||
public interface AfterReturningAdvice extends AfterAdvice {
|
||||
|
||||
/**
|
||||
* Callback after a given method successfully returned.
|
||||
* @param returnValue the value returned by the method, if any
|
||||
* @param method method being invoked
|
||||
* @param args arguments to the method
|
||||
* @param target target of the method invocation. May be <code>null</code>.
|
||||
* @throws Throwable if this object wishes to abort the call.
|
||||
* Any exception thrown will be returned to the caller if it's
|
||||
* allowed by the method signature. Otherwise the exception
|
||||
* will be wrapped as a runtime exception.
|
||||
*/
|
||||
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Exception that gets thrown when an AOP invocation failed
|
||||
* because of misconfiguration or unexpected runtime issues.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AopInvocationException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Constructor for AopInvocationException.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AopInvocationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for AopInvocationException.
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
*/
|
||||
public AopInvocationException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
/**
|
||||
* Common marker interface for before advice, such as {@link MethodBeforeAdvice}.
|
||||
*
|
||||
* <p>Spring supports only method before advice. Although this is unlikely to change,
|
||||
* this API is designed to allow field advice in future if desired.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see AfterAdvice
|
||||
*/
|
||||
public interface BeforeAdvice extends Advice {
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Filter that restricts matching of a pointcut or introduction to
|
||||
* a given set of target classes.
|
||||
*
|
||||
* <p>Can be used as part of a {@link Pointcut} or for the entire
|
||||
* targeting of an {@link IntroductionAdvisor}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see Pointcut
|
||||
* @see MethodMatcher
|
||||
*/
|
||||
public interface ClassFilter {
|
||||
|
||||
/**
|
||||
* Should the pointcut apply to the given interface or target class?
|
||||
* @param clazz the candidate target class
|
||||
* @return whether the advice should apply to the given target class
|
||||
*/
|
||||
boolean matches(Class<?> clazz);
|
||||
|
||||
|
||||
/**
|
||||
* Canonical instance of a ClassFilter that matches all classes.
|
||||
*/
|
||||
ClassFilter TRUE = TrueClassFilter.INSTANCE;
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
/**
|
||||
* Subinterface of AOP Alliance Advice that allows additional interfaces
|
||||
* to be implemented by an Advice, and available via a proxy using that
|
||||
* interceptor. This is a fundamental AOP concept called <b>introduction</b>.
|
||||
*
|
||||
* <p>Introductions are often <b>mixins</b>, enabling the building of composite
|
||||
* objects that can achieve many of the goals of multiple inheritance in Java.
|
||||
*
|
||||
* <p>Compared to {qlink IntroductionInfo}, this interface allows an advice to
|
||||
* implement a range of interfaces that is not necessarily known in advance.
|
||||
* Thus an {@link IntroductionAdvisor} can be used to specify which interfaces
|
||||
* will be exposed in an advised object.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 1.1.1
|
||||
* @see IntroductionInfo
|
||||
* @see IntroductionAdvisor
|
||||
*/
|
||||
public interface DynamicIntroductionAdvice extends Advice {
|
||||
|
||||
/**
|
||||
* Does this introduction advice implement the given interface?
|
||||
* @param intf the interface to check
|
||||
* @return whether the advice implements the specified interface
|
||||
*/
|
||||
boolean implementsInterface(Class<?> intf);
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Superinterface for advisors that perform one or more AOP <b>introductions</b>.
|
||||
*
|
||||
* <p>This interface cannot be implemented directly; subinterfaces must
|
||||
* provide the advice type implementing the introduction.
|
||||
*
|
||||
* <p>Introduction is the implementation of additional interfaces
|
||||
* (not implemented by a target) via AOP advice.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 04.04.2003
|
||||
* @see IntroductionInterceptor
|
||||
*/
|
||||
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
|
||||
|
||||
/**
|
||||
* Return the filter determining which target classes this introduction
|
||||
* should apply to.
|
||||
* <p>This represents the class part of a pointcut. Note that method
|
||||
* matching doesn't make sense to introductions.
|
||||
* @return the class filter
|
||||
*/
|
||||
ClassFilter getClassFilter();
|
||||
|
||||
/**
|
||||
* Can the advised interfaces be implemented by the introduction advice?
|
||||
* Invoked before adding an IntroductionAdvisor.
|
||||
* @throws IllegalArgumentException if the advised interfaces can't be
|
||||
* implemented by the introduction advice
|
||||
*/
|
||||
void validateInterfaces() throws IllegalArgumentException;
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A specialized type of MethodMatcher that takes into account introductions when
|
||||
* matching methods. If there are no introductions on the target class, a method
|
||||
* matcher may be able to optimize matching more effectively for example.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface IntroductionAwareMethodMatcher extends MethodMatcher {
|
||||
|
||||
/**
|
||||
* Perform static checking whether the given method matches. This may be invoked
|
||||
* instead of the 2-arg {@link #matches(java.lang.reflect.Method, Class)} method
|
||||
* if the caller supports the extended IntroductionAwareMethodMatcher interface.
|
||||
* @param method the candidate method
|
||||
* @param targetClass the target class (may be <code>null</code>, in which case
|
||||
* the candidate class must be taken to be the method's declaring class)
|
||||
* @param hasIntroductions <code>true</code> if the object on whose behalf we are
|
||||
* asking is the subject on one or more introductions; <code>false</code> otherwise
|
||||
* @return whether or not this method matches statically
|
||||
*/
|
||||
boolean matches(Method method, Class targetClass, boolean hasIntroductions);
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Interface supplying the information necessary to describe an introduction.
|
||||
*
|
||||
* <p>{@link IntroductionAdvisor IntroductionAdvisors} must implement this
|
||||
* interface. If an {@link org.aopalliance.aop.Advice} implements this,
|
||||
* it may be used as an introduction without an {@link IntroductionAdvisor}.
|
||||
* In this case, the advice is self-describing, providing not only the
|
||||
* necessary behavior, but describing the interfaces it introduces.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 1.1.1
|
||||
*/
|
||||
public interface IntroductionInfo {
|
||||
|
||||
/**
|
||||
* Return the additional interfaces introduced by this Advisor or Advice.
|
||||
* @return the introduced interfaces
|
||||
*/
|
||||
Class[] getInterfaces();
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
|
||||
/**
|
||||
* Subinterface of AOP Alliance MethodInterceptor that allows additional interfaces
|
||||
* to be implemented by the interceptor, and available via a proxy using that
|
||||
* interceptor. This is a fundamental AOP concept called <b>introduction</b>.
|
||||
*
|
||||
* <p>Introductions are often <b>mixins</b>, enabling the building of composite
|
||||
* objects that can achieve many of the goals of multiple inheritance in Java.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see DynamicIntroductionAdvice
|
||||
*/
|
||||
public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Advice invoked before a method is invoked. Such advices cannot
|
||||
* prevent the method call proceeding, unless they throw a Throwable.
|
||||
*
|
||||
* @see AfterReturningAdvice
|
||||
* @see ThrowsAdvice
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public interface MethodBeforeAdvice extends BeforeAdvice {
|
||||
|
||||
/**
|
||||
* Callback before a given method is invoked.
|
||||
* @param method method being invoked
|
||||
* @param args arguments to the method
|
||||
* @param target target of the method invocation. May be <code>null</code>.
|
||||
* @throws Throwable if this object wishes to abort the call.
|
||||
* Any exception thrown will be returned to the caller if it's
|
||||
* allowed by the method signature. Otherwise the exception
|
||||
* will be wrapped as a runtime exception.
|
||||
*/
|
||||
void before(Method method, Object[] args, Object target) throws Throwable;
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
|
||||
*
|
||||
* <p>A MethodMatcher may be evaluated <b>statically</b> or at <b>runtime</b> (dynamically).
|
||||
* Static matching involves method and (possibly) method attributes. Dynamic matching
|
||||
* also makes arguments for a particular call available, and any effects of running
|
||||
* previous advice applying to the joinpoint.
|
||||
*
|
||||
* <p>If an implementation returns <code>false</code> from its {@link #isRuntime()}
|
||||
* method, evaluation can be performed statically, and the result will be the same
|
||||
* for all invocations of this method, whatever their arguments. This means that
|
||||
* if the {@link #isRuntime()} method returns <code>false</code>, the 3-arg
|
||||
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method will never be invoked.
|
||||
*
|
||||
* <p>If an implementation returns <code>true</code> from its 2-arg
|
||||
* {@link #matches(java.lang.reflect.Method, Class)} method and its {@link #isRuntime()} method
|
||||
* returns <code>true</code>, the 3-arg {@link #matches(java.lang.reflect.Method, Class, Object[])}
|
||||
* method will be invoked <i>immediately before each potential execution of the related advice</i>,
|
||||
* to decide whether the advice should run. All previous advice, such as earlier interceptors
|
||||
* in an interceptor chain, will have run, so any state changes they have produced in
|
||||
* parameters or ThreadLocal state will be available at the time of evaluation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 11.11.2003
|
||||
* @see Pointcut
|
||||
* @see ClassFilter
|
||||
*/
|
||||
public interface MethodMatcher {
|
||||
|
||||
/**
|
||||
* Perform static checking whether the given method matches. If this
|
||||
* returns <code>false</code> or if the {@link #isRuntime()} method
|
||||
* returns <code>false</code>, no runtime check (i.e. no.
|
||||
* {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made.
|
||||
* @param method the candidate method
|
||||
* @param targetClass the target class (may be <code>null</code>, in which case
|
||||
* the candidate class must be taken to be the method's declaring class)
|
||||
* @return whether or not this method matches statically
|
||||
*/
|
||||
boolean matches(Method method, Class<?> targetClass);
|
||||
|
||||
/**
|
||||
* Is this MethodMatcher dynamic, that is, must a final call be made on the
|
||||
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method at
|
||||
* runtime even if the 2-arg matches method returns <code>true</code>?
|
||||
* <p>Can be invoked when an AOP proxy is created, and need not be invoked
|
||||
* again before each method invocation,
|
||||
* @return whether or not a runtime match via the 3-arg
|
||||
* {@link #matches(java.lang.reflect.Method, Class, Object[])} method
|
||||
* is required if static matching passed
|
||||
*/
|
||||
boolean isRuntime();
|
||||
|
||||
/**
|
||||
* Check whether there a runtime (dynamic) match for this method,
|
||||
* which must have matched statically.
|
||||
* <p>This method is invoked only if the 2-arg matches method returns
|
||||
* <code>true</code> for the given method and target class, and if the
|
||||
* {@link #isRuntime()} method returns <code>true</code>. Invoked
|
||||
* immediately before potential running of the advice, after any
|
||||
* advice earlier in the advice chain has run.
|
||||
* @param method the candidate method
|
||||
* @param targetClass the target class (may be <code>null</code>, in which case
|
||||
* the candidate class must be taken to be the method's declaring class)
|
||||
* @param args arguments to the method
|
||||
* @return whether there's a runtime match
|
||||
* @see MethodMatcher#matches(Method, Class)
|
||||
*/
|
||||
boolean matches(Method method, Class<?> targetClass, Object[] args);
|
||||
|
||||
|
||||
/**
|
||||
* Canonical instance that matches all methods.
|
||||
*/
|
||||
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Core Spring pointcut abstraction.
|
||||
*
|
||||
* <p>A pointcut is composed of a {@link ClassFilter} and a {@link MethodMatcher}.
|
||||
* Both these basic terms and a Pointcut itself can be combined to build up combinations
|
||||
* (e.g. through {@link org.springframework.aop.support.ComposablePointcut}).
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see ClassFilter
|
||||
* @see MethodMatcher
|
||||
* @see org.springframework.aop.support.Pointcuts
|
||||
* @see org.springframework.aop.support.ClassFilters
|
||||
* @see org.springframework.aop.support.MethodMatchers
|
||||
*/
|
||||
public interface Pointcut {
|
||||
|
||||
/**
|
||||
* Return the ClassFilter for this pointcut.
|
||||
* @return the ClassFilter (never <code>null</code>)
|
||||
*/
|
||||
ClassFilter getClassFilter();
|
||||
|
||||
/**
|
||||
* Return the MethodMatcher for this pointcut.
|
||||
* @return the MethodMatcher (never <code>null</code>)
|
||||
*/
|
||||
MethodMatcher getMethodMatcher();
|
||||
|
||||
|
||||
/**
|
||||
* Canonical Pointcut instance that always matches.
|
||||
*/
|
||||
Pointcut TRUE = TruePointcut.INSTANCE;
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Superinterface for all Advisors that are driven by a pointcut.
|
||||
* This covers nearly all advisors except introduction advisors,
|
||||
* for which method-level matching doesn't apply.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public interface PointcutAdvisor extends Advisor {
|
||||
|
||||
/**
|
||||
* Get the Pointcut that drives this advisor.
|
||||
*/
|
||||
Pointcut getPointcut();
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
/**
|
||||
* Extension of the AOP Alliance {@link org.aopalliance.intercept.MethodInvocation}
|
||||
* interface, allowing access to the proxy that the method invocation was made through.
|
||||
*
|
||||
* <p>Useful to be able to substitute return values with the proxy,
|
||||
* if necessary, for example if the invocation target returned itself.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Adrian Colyer
|
||||
* @since 1.1.3
|
||||
* @see org.springframework.aop.framework.ReflectiveMethodInvocation
|
||||
* @see org.springframework.aop.support.DelegatingIntroductionInterceptor
|
||||
*/
|
||||
public interface ProxyMethodInvocation extends MethodInvocation {
|
||||
|
||||
/**
|
||||
* Return the proxy that this method invocation was made through.
|
||||
* @return the original proxy object
|
||||
*/
|
||||
Object getProxy();
|
||||
|
||||
/**
|
||||
* Create a clone of this object. If cloning is done before <code>proceed()</code>
|
||||
* is invoked on this object, <code>proceed()</code> can be invoked once per clone
|
||||
* to invoke the joinpoint (and the rest of the advice chain) more than once.
|
||||
* @return an invocable clone of this invocation.
|
||||
* <code>proceed()</code> can be called once per clone.
|
||||
*/
|
||||
MethodInvocation invocableClone();
|
||||
|
||||
/**
|
||||
* Create a clone of this object. If cloning is done before <code>proceed()</code>
|
||||
* is invoked on this object, <code>proceed()</code> can be invoked once per clone
|
||||
* to invoke the joinpoint (and the rest of the advice chain) more than once.
|
||||
* @param arguments the arguments that the cloned invocation is supposed to use,
|
||||
* overriding the original arguments
|
||||
* @return an invocable clone of this invocation.
|
||||
* <code>proceed()</code> can be called once per clone.
|
||||
*/
|
||||
MethodInvocation invocableClone(Object[] arguments);
|
||||
|
||||
/**
|
||||
* Set the arguments to be used on subsequent invocations in the any advice
|
||||
* in this chain.
|
||||
* @param arguments the argument array
|
||||
*/
|
||||
void setArguments(Object[] arguments);
|
||||
|
||||
/**
|
||||
* Add the specified user attribute with the given value to this invocation.
|
||||
* <p>Such attributes are not used within the AOP framework itself. They are
|
||||
* just kept as part of the invocation object, for use in special interceptors.
|
||||
* @param key the name of the attribute
|
||||
* @param value the value of the attribute, or <code>null</code> to reset it
|
||||
*/
|
||||
void setUserAttribute(String key, Object value);
|
||||
|
||||
/**
|
||||
* Return the value of the specified user attribute.
|
||||
* @param key the name of the attribute
|
||||
* @return the value of the attribute, or <code>null</code> if not set
|
||||
* @see #setUserAttribute
|
||||
*/
|
||||
Object getUserAttribute(String key);
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Marker for AOP proxy interfaces (in particular: introduction interfaces)
|
||||
* that explicitly intend to return the raw target object (which would normally
|
||||
* get replaced with the proxy object when returned from a method invocation).
|
||||
*
|
||||
* <p>Note that this is a marker interface in the style of {@link java.io.Serializable},
|
||||
* semantically applying to a declared interface rather than to the full class
|
||||
* of a concrete object. In other words, this marker applies to a particular
|
||||
* interface only (typically an introduction interface that does not serve
|
||||
* as the primary interface of an AOP proxy), and hence does not affect
|
||||
* other interfaces that a concrete AOP proxy may implement.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.5
|
||||
* @see org.springframework.aop.scope.ScopedObject
|
||||
*/
|
||||
public interface RawTargetAccess {
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Marker interface implemented by all AOP proxies. Used to detect
|
||||
* whether or not objects are Spring-generated proxies.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @since 2.0.1
|
||||
* @see org.springframework.aop.support.AopUtils#isAopProxy(Object)
|
||||
*/
|
||||
public interface SpringProxy {
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Minimal interface for exposing the target class behind a proxy.
|
||||
*
|
||||
* <p>Implemented by AOP proxy objects and proxy factories
|
||||
* (via {@link org.springframework.aop.framework.Advised}}
|
||||
* as well as by {@link TargetSource TargetSources}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.3
|
||||
* @see org.springframework.aop.support.AopUtils#getTargetClass(Object)
|
||||
*/
|
||||
public interface TargetClassAware {
|
||||
|
||||
/**
|
||||
* Return the target class behind the implementing object
|
||||
* (typically a proxy configuration or an actual proxy).
|
||||
* @return the target Class, or <code>null</code> if not known
|
||||
*/
|
||||
Class<?> getTargetClass();
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*<
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* A <code>TargetSource</code> is used to obtain the current "target" of
|
||||
* an AOP invocation, which will be invoked via reflection if no around
|
||||
* advice chooses to end the interceptor chain itself.
|
||||
*
|
||||
* <p>If a <code>TargetSource</code> is "static", it will always return
|
||||
* the same target, allowing optimizations in the AOP framework. Dynamic
|
||||
* target sources can support pooling, hot swapping, etc.
|
||||
*
|
||||
* <p>Application developers don't usually need to work with
|
||||
* <code>TargetSources</code> directly: this is an AOP framework interface.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public interface TargetSource extends TargetClassAware {
|
||||
|
||||
/**
|
||||
* Return the type of targets returned by this {@link TargetSource}.
|
||||
* <p>Can return <code>null</code>, although certain usages of a
|
||||
* <code>TargetSource</code> might just work with a predetermined
|
||||
* target class.
|
||||
* @return the type of targets returned by this {@link TargetSource}
|
||||
*/
|
||||
Class<?> getTargetClass();
|
||||
|
||||
/**
|
||||
* Will all calls to {@link #getTarget()} return the same object?
|
||||
* <p>In that case, there will be no need to invoke
|
||||
* {@link #releaseTarget(Object)}, and the AOP framework can cache
|
||||
* the return value of {@link #getTarget()}.
|
||||
* @return <code>true</code> if the target is immutable
|
||||
* @see #getTarget
|
||||
*/
|
||||
boolean isStatic();
|
||||
|
||||
/**
|
||||
* Return a target instance. Invoked immediately before the
|
||||
* AOP framework calls the "target" of an AOP method invocation.
|
||||
* @return the target object, which contains the joinpoint
|
||||
* @throws Exception if the target object can't be resolved
|
||||
*/
|
||||
Object getTarget() throws Exception;
|
||||
|
||||
/**
|
||||
* Release the given target object obtained from the
|
||||
* {@link #getTarget()} method.
|
||||
* @param target object obtained from a call to {@link #getTarget()}
|
||||
* @throws Exception if the object can't be released
|
||||
*/
|
||||
void releaseTarget(Object target) throws Exception;
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
/**
|
||||
* Tag interface for throws advice.
|
||||
*
|
||||
* <p>There are not any methods on this interface, as methods are invoked by
|
||||
* reflection. Implementing classes must implement methods of the form:
|
||||
*
|
||||
* <pre class="code">void afterThrowing([Method, args, target], ThrowableSubclass);</pre>
|
||||
*
|
||||
* <p>Some examples of valid methods would be:
|
||||
*
|
||||
* <pre class="code">public void afterThrowing(Exception ex)</pre>
|
||||
* <pre class="code">public void afterThrowing(RemoteException)</pre>
|
||||
* <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre>
|
||||
* <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre>
|
||||
*
|
||||
* The first three arguments are optional, and only useful if we want further
|
||||
* information about the joinpoint, as in AspectJ <b>after-throwing</b> advice.
|
||||
*
|
||||
* <p><b>Note:</b> If a throws-advice method throws an exception itself, it will
|
||||
* override the original exception (i.e. change the exception thrown to the user).
|
||||
* The overriding exception will typically be a RuntimeException; this is compatible
|
||||
* with any method signature. However, if a throws-advice method throws a checked
|
||||
* exception, it will have to match the declared exceptions of the target method
|
||||
* and is hence to some degree coupled to specific target method signatures.
|
||||
* <b>Do not throw an undeclared checked exception that is incompatible with
|
||||
* the target method's signature!</b>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see AfterReturningAdvice
|
||||
* @see MethodBeforeAdvice
|
||||
*/
|
||||
public interface ThrowsAdvice extends AfterAdvice {
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Canonical ClassFilter instance that matches all classes.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
class TrueClassFilter implements ClassFilter, Serializable {
|
||||
|
||||
public static final TrueClassFilter INSTANCE = new TrueClassFilter();
|
||||
|
||||
/**
|
||||
* Enforce Singleton pattern.
|
||||
*/
|
||||
private TrueClassFilter() {
|
||||
}
|
||||
|
||||
public boolean matches(Class clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required to support serialization. Replaces with canonical
|
||||
* instance on deserialization, protecting Singleton pattern.
|
||||
* Alternative to overriding <code>equals()</code>.
|
||||
*/
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClassFilter.TRUE";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Canonical MethodMatcher instance that matches all methods.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
class TrueMethodMatcher implements MethodMatcher, Serializable {
|
||||
|
||||
public static final TrueMethodMatcher INSTANCE = new TrueMethodMatcher();
|
||||
|
||||
/**
|
||||
* Enforce Singleton pattern.
|
||||
*/
|
||||
private TrueMethodMatcher() {
|
||||
}
|
||||
|
||||
public boolean isRuntime() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
// Should never be invoked as isRuntime returns false.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Required to support serialization. Replaces with canonical
|
||||
* instance on deserialization, protecting Singleton pattern.
|
||||
* Alternative to overriding <code>equals()</code>.
|
||||
*/
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodMatcher.TRUE";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Canonical Pointcut instance that always matches.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
class TruePointcut implements Pointcut, Serializable {
|
||||
|
||||
public static final TruePointcut INSTANCE = new TruePointcut();
|
||||
|
||||
/**
|
||||
* Enforce Singleton pattern.
|
||||
*/
|
||||
private TruePointcut() {
|
||||
}
|
||||
|
||||
public ClassFilter getClassFilter() {
|
||||
return ClassFilter.TRUE;
|
||||
}
|
||||
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
return MethodMatcher.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required to support serialization. Replaces with canonical
|
||||
* instance on deserialization, protecting Singleton pattern.
|
||||
* Alternative to overriding <code>equals()</code>.
|
||||
*/
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pointcut.TRUE";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,703 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.weaver.tools.JoinPointMatch;
|
||||
import org.aspectj.weaver.tools.PointcutParameter;
|
||||
|
||||
import org.springframework.aop.AopInvocationException;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.ProxyMethodInvocation;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.aop.support.ComposablePointcut;
|
||||
import org.springframework.aop.support.MethodMatchers;
|
||||
import org.springframework.aop.support.StaticMethodMatcher;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.PrioritizedParameterNameDiscoverer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for AOP Alliance {@link org.aopalliance.aop.Advice} classes
|
||||
* wrapping an AspectJ aspect or an AspectJ-annotated advice method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation {
|
||||
|
||||
/**
|
||||
* Key used in ReflectiveMethodInvocation userAtributes map for the current joinpoint.
|
||||
*/
|
||||
protected static final String JOIN_POINT_KEY = JoinPoint.class.getName();
|
||||
|
||||
|
||||
/**
|
||||
* Lazily instantiate joinpoint for the current invocation.
|
||||
* Requires MethodInvocation to be bound with ExposeInvocationInterceptor.
|
||||
* <p>Do not use if access is available to the current ReflectiveMethodInvocation
|
||||
* (in an around advice).
|
||||
* @return current AspectJ joinpoint, or through an exception if we're not in a
|
||||
* Spring AOP invocation.
|
||||
*/
|
||||
public static JoinPoint currentJoinPoint() {
|
||||
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
|
||||
if (!(mi instanceof ProxyMethodInvocation)) {
|
||||
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
|
||||
}
|
||||
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
|
||||
JoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY);
|
||||
if (jp == null) {
|
||||
jp = new MethodInvocationProceedingJoinPoint(pmi);
|
||||
pmi.setUserAttribute(JOIN_POINT_KEY, jp);
|
||||
}
|
||||
return jp;
|
||||
}
|
||||
|
||||
|
||||
protected final Method aspectJAdviceMethod;
|
||||
|
||||
/** The total number of arguments we have to populate on advice dispatch */
|
||||
private final int adviceInvocationArgumentCount;
|
||||
|
||||
private final AspectJExpressionPointcut pointcut;
|
||||
|
||||
private final AspectInstanceFactory aspectInstanceFactory;
|
||||
|
||||
/**
|
||||
* The name of the aspect (ref bean) in which this advice was defined (used
|
||||
* when determining advice precedence so that we can determine
|
||||
* whether two pieces of advice come from the same aspect).
|
||||
*/
|
||||
private String aspectName;
|
||||
|
||||
/**
|
||||
* The order of declaration of this advice within the aspect.
|
||||
*/
|
||||
private int declarationOrder;
|
||||
|
||||
/**
|
||||
* This will be non-null if the creator of this advice object knows the argument names
|
||||
* and sets them explicitly
|
||||
*/
|
||||
private String[] argumentNames = null;
|
||||
|
||||
/** Non-null if after throwing advice binds the thrown value */
|
||||
private String throwingName = null;
|
||||
|
||||
/** Non-null if after returning advice binds the return value */
|
||||
private String returningName = null;
|
||||
|
||||
private Class discoveredReturningType = Object.class;
|
||||
|
||||
private Class discoveredThrowingType = Object.class;
|
||||
|
||||
/**
|
||||
* Index for thisJoinPoint argument (currently only
|
||||
* supported at index 0 if present at all)
|
||||
*/
|
||||
private int joinPointArgumentIndex = -1;
|
||||
|
||||
/**
|
||||
* Index for thisJoinPointStaticPart argument (currently only
|
||||
* supported at index 0 if present at all)
|
||||
*/
|
||||
private int joinPointStaticPartArgumentIndex = -1;
|
||||
|
||||
private Map<String, Integer> argumentBindings = null;
|
||||
|
||||
private boolean argumentsIntrospected = false;
|
||||
|
||||
private Type discoveredReturningGenericType;
|
||||
// Note: Unlike return type, no such generic information is needed for the throwing type,
|
||||
// since Java doesn't allow exception types to be parameterized.
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AbstractAspectJAdvice for the given advice method.
|
||||
* @param aspectJAdviceMethod the AspectJ-style advice method
|
||||
* @param pointcut the AspectJ expression pointcut
|
||||
* @param aspectInstanceFactory the factory for aspect instances
|
||||
*/
|
||||
public AbstractAspectJAdvice(
|
||||
Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
|
||||
|
||||
Assert.notNull(aspectJAdviceMethod, "Advice method must not be null");
|
||||
this.aspectJAdviceMethod = aspectJAdviceMethod;
|
||||
this.adviceInvocationArgumentCount = this.aspectJAdviceMethod.getParameterTypes().length;
|
||||
this.pointcut = pointcut;
|
||||
this.aspectInstanceFactory = aspectInstanceFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the AspectJ-style advice method.
|
||||
*/
|
||||
public final Method getAspectJAdviceMethod() {
|
||||
return this.aspectJAdviceMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AspectJ expression pointcut.
|
||||
*/
|
||||
public final AspectJExpressionPointcut getPointcut() {
|
||||
calculateArgumentBindings();
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a 'safe' pointcut that excludes the AspectJ advice method itself.
|
||||
* @return a composable pointcut that builds on the original AspectJ expression pointcut
|
||||
* @see #getPointcut()
|
||||
*/
|
||||
public final Pointcut buildSafePointcut() {
|
||||
Pointcut pc = getPointcut();
|
||||
MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
|
||||
new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
|
||||
return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the factory for aspect instances.
|
||||
*/
|
||||
public final AspectInstanceFactory getAspectInstanceFactory() {
|
||||
return this.aspectInstanceFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ClassLoader for aspect instances.
|
||||
*/
|
||||
public final ClassLoader getAspectClassLoader() {
|
||||
return this.aspectInstanceFactory.getAspectClassLoader();
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return this.aspectInstanceFactory.getOrder();
|
||||
}
|
||||
|
||||
|
||||
public void setAspectName(String name) {
|
||||
this.aspectName = name;
|
||||
}
|
||||
|
||||
public String getAspectName() {
|
||||
return this.aspectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <b>declaration order</b> of this advice within the aspect
|
||||
*/
|
||||
public void setDeclarationOrder(int order) {
|
||||
this.declarationOrder = order;
|
||||
}
|
||||
|
||||
public int getDeclarationOrder() {
|
||||
return this.declarationOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by creator of this advice object if the argument names are known.
|
||||
* <p>This could be for example because they have been explicitly specified in XML,
|
||||
* or in an advice annotation.
|
||||
* @param argNames comma delimited list of arg names
|
||||
*/
|
||||
public void setArgumentNames(String argNames) {
|
||||
String[] tokens = StringUtils.commaDelimitedListToStringArray(argNames);
|
||||
setArgumentNamesFromStringArray(tokens);
|
||||
}
|
||||
|
||||
public void setArgumentNamesFromStringArray(String[] args) {
|
||||
this.argumentNames = new String[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
this.argumentNames[i] = StringUtils.trimWhitespace(args[i]);
|
||||
if (!isVariableName(this.argumentNames[i])) {
|
||||
throw new IllegalArgumentException(
|
||||
"'argumentNames' property of AbstractAspectJAdvice contains an argument name '" +
|
||||
this.argumentNames[i] + "' that is not a valid Java identifier");
|
||||
}
|
||||
}
|
||||
if (argumentNames != null) {
|
||||
if (aspectJAdviceMethod.getParameterTypes().length == argumentNames.length + 1) {
|
||||
// May need to add implicit join point arg name...
|
||||
Class firstArgType = aspectJAdviceMethod.getParameterTypes()[0];
|
||||
if (firstArgType == JoinPoint.class ||
|
||||
firstArgType == ProceedingJoinPoint.class ||
|
||||
firstArgType == JoinPoint.StaticPart.class) {
|
||||
String[] oldNames = argumentNames;
|
||||
argumentNames = new String[oldNames.length + 1];
|
||||
argumentNames[0] = "THIS_JOIN_POINT";
|
||||
System.arraycopy(oldNames, 0, argumentNames, 1, oldNames.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setReturningName(String name) {
|
||||
throw new UnsupportedOperationException("Only afterReturning advice can be used to bind a return value");
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to hold the returning name at this level for argument binding calculations,
|
||||
* this method allows the afterReturning advice subclass to set the name.
|
||||
*/
|
||||
protected void setReturningNameNoCheck(String name) {
|
||||
// name could be a variable or a type...
|
||||
if (isVariableName(name)) {
|
||||
this.returningName = name;
|
||||
}
|
||||
else {
|
||||
// assume a type
|
||||
try {
|
||||
this.discoveredReturningType = ClassUtils.forName(name, getAspectClassLoader());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Returning name '" + name +
|
||||
"' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. " +
|
||||
"Root cause: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Class getDiscoveredReturningType() {
|
||||
return this.discoveredReturningType;
|
||||
}
|
||||
|
||||
protected Type getDiscoveredReturningGenericType() {
|
||||
return this.discoveredReturningGenericType;
|
||||
}
|
||||
|
||||
public void setThrowingName(String name) {
|
||||
throw new UnsupportedOperationException("Only afterThrowing advice can be used to bind a thrown exception");
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to hold the throwing name at this level for argument binding calculations,
|
||||
* this method allows the afterThrowing advice subclass to set the name.
|
||||
*/
|
||||
protected void setThrowingNameNoCheck(String name) {
|
||||
// name could be a variable or a type...
|
||||
if (isVariableName(name)) {
|
||||
this.throwingName = name;
|
||||
}
|
||||
else {
|
||||
// assume a type
|
||||
try {
|
||||
this.discoveredThrowingType = ClassUtils.forName(name, getAspectClassLoader());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Throwing name '" + name +
|
||||
"' is neither a valid argument name nor the fully-qualified name of a Java type on the classpath. " +
|
||||
"Root cause: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Class getDiscoveredThrowingType() {
|
||||
return this.discoveredThrowingType;
|
||||
}
|
||||
|
||||
private boolean isVariableName(String name) {
|
||||
char[] chars = name.toCharArray();
|
||||
if (!Character.isJavaIdentifierStart(chars[0])) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < chars.length; i++) {
|
||||
if (!Character.isJavaIdentifierPart(chars[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do as much work as we can as part of the set-up so that argument binding
|
||||
* on subsequent advice invocations can be as fast as possible.
|
||||
* <p>If the first argument is of type JoinPoint or ProceedingJoinPoint then we
|
||||
* pass a JoinPoint in that position (ProceedingJoinPoint for around advice).
|
||||
* <p>If the first argument is of type <code>JoinPoint.StaticPart</code>
|
||||
* then we pass a <code>JoinPoint.StaticPart</code> in that position.
|
||||
* <p>Remaining arguments have to be bound by pointcut evaluation at
|
||||
* a given join point. We will get back a map from argument name to
|
||||
* value. We need to calculate which advice parameter needs to be bound
|
||||
* to which argument name. There are multiple strategies for determining
|
||||
* this binding, which are arranged in a ChainOfResponsibility.
|
||||
*/
|
||||
public synchronized final void calculateArgumentBindings() {
|
||||
// The simple case... nothing to bind.
|
||||
if (this.argumentsIntrospected || this.adviceInvocationArgumentCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numUnboundArgs = this.adviceInvocationArgumentCount;
|
||||
Class[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
|
||||
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
|
||||
numUnboundArgs--;
|
||||
}
|
||||
else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
|
||||
numUnboundArgs--;
|
||||
}
|
||||
|
||||
if (numUnboundArgs > 0) {
|
||||
// need to bind arguments by name as returned from the pointcut match
|
||||
bindArgumentsByName(numUnboundArgs);
|
||||
}
|
||||
|
||||
this.argumentsIntrospected = true;
|
||||
}
|
||||
|
||||
private boolean maybeBindJoinPoint(Class candidateParameterType) {
|
||||
if (candidateParameterType.equals(JoinPoint.class)) {
|
||||
this.joinPointArgumentIndex = 0;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean maybeBindProceedingJoinPoint(Class candidateParameterType) {
|
||||
if (candidateParameterType.equals(ProceedingJoinPoint.class)) {
|
||||
if (!supportsProceedingJoinPoint()) {
|
||||
throw new IllegalArgumentException("ProceedingJoinPoint is only supported for around advice");
|
||||
}
|
||||
this.joinPointArgumentIndex = 0;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean supportsProceedingJoinPoint() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean maybeBindJoinPointStaticPart(Class candidateParameterType) {
|
||||
if (candidateParameterType.equals(JoinPoint.StaticPart.class)) {
|
||||
this.joinPointStaticPartArgumentIndex = 0;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void bindArgumentsByName(int numArgumentsExpectingToBind) {
|
||||
if (this.argumentNames == null) {
|
||||
this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
|
||||
}
|
||||
if (this.argumentNames != null) {
|
||||
// We have been able to determine the arg names.
|
||||
bindExplicitArguments(numArgumentsExpectingToBind);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Advice method [" + this.aspectJAdviceMethod.getName() + "] " +
|
||||
"requires " + numArgumentsExpectingToBind + " arguments to be bound by name, but " +
|
||||
"the argument names were not specified and could not be discovered.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ParameterNameDiscoverer to be used for argument binding.
|
||||
* <p>The default implementation creates a {@link PrioritizedParameterNameDiscoverer}
|
||||
* containing a {@link LocalVariableTableParameterNameDiscoverer} and an
|
||||
* {@link AspectJAdviceParameterNameDiscoverer}.
|
||||
*/
|
||||
protected ParameterNameDiscoverer createParameterNameDiscoverer() {
|
||||
// We need to discover them, or if that fails, guess,
|
||||
// and if we can't guess with 100% accuracy, fail.
|
||||
PrioritizedParameterNameDiscoverer discoverer = new PrioritizedParameterNameDiscoverer();
|
||||
discoverer.addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
|
||||
AspectJAdviceParameterNameDiscoverer adviceParameterNameDiscoverer =
|
||||
new AspectJAdviceParameterNameDiscoverer(this.pointcut.getExpression());
|
||||
adviceParameterNameDiscoverer.setReturningName(this.returningName);
|
||||
adviceParameterNameDiscoverer.setThrowingName(this.throwingName);
|
||||
// Last in chain, so if we're called and we fail, that's bad...
|
||||
adviceParameterNameDiscoverer.setRaiseExceptions(true);
|
||||
discoverer.addDiscoverer(adviceParameterNameDiscoverer);
|
||||
return discoverer;
|
||||
}
|
||||
|
||||
private void bindExplicitArguments(int numArgumentsLeftToBind) {
|
||||
this.argumentBindings = new HashMap<String, Integer>();
|
||||
|
||||
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length;
|
||||
if (this.argumentNames.length != numExpectedArgumentNames) {
|
||||
throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames
|
||||
+ " arguments to bind by name in advice, but actually found " +
|
||||
this.argumentNames.length + " arguments.");
|
||||
}
|
||||
|
||||
// So we match in number...
|
||||
int argumentIndexOffset = this.adviceInvocationArgumentCount - numArgumentsLeftToBind;
|
||||
for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
|
||||
this.argumentBindings.put(this.argumentNames[i], i);
|
||||
}
|
||||
|
||||
// Check that returning and throwing were in the argument names list if
|
||||
// specified, and find the discovered argument types.
|
||||
if (this.returningName != null) {
|
||||
if (!this.argumentBindings.containsKey(this.returningName)) {
|
||||
throw new IllegalStateException("Returning argument name '"
|
||||
+ this.returningName + "' was not bound in advice arguments");
|
||||
}
|
||||
else {
|
||||
Integer index = this.argumentBindings.get(this.returningName);
|
||||
this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
|
||||
this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
|
||||
}
|
||||
}
|
||||
if (this.throwingName != null) {
|
||||
if (!this.argumentBindings.containsKey(this.throwingName)) {
|
||||
throw new IllegalStateException("Throwing argument name '"
|
||||
+ this.throwingName + "' was not bound in advice arguments");
|
||||
}
|
||||
else {
|
||||
Integer index = this.argumentBindings.get(this.throwingName);
|
||||
this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
|
||||
}
|
||||
}
|
||||
|
||||
// configure the pointcut expression accordingly.
|
||||
configurePointcutParameters(argumentIndexOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* All parameters from argumentIndexOffset onwards are candidates for
|
||||
* pointcut parameters - but returning and throwing vars are handled differently
|
||||
* and must be removed from the list if present.
|
||||
*/
|
||||
private void configurePointcutParameters(int argumentIndexOffset) {
|
||||
int numParametersToRemove = argumentIndexOffset;
|
||||
if (this.returningName != null) {
|
||||
numParametersToRemove++;
|
||||
}
|
||||
if (this.throwingName != null) {
|
||||
numParametersToRemove++;
|
||||
}
|
||||
String[] pointcutParameterNames = new String[this.argumentNames.length - numParametersToRemove];
|
||||
Class[] pointcutParameterTypes = new Class[pointcutParameterNames.length];
|
||||
Class[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < this.argumentNames.length; i++) {
|
||||
if (i < argumentIndexOffset) {
|
||||
continue;
|
||||
}
|
||||
if (this.argumentNames[i].equals(this.returningName) ||
|
||||
this.argumentNames[i].equals(this.throwingName)) {
|
||||
continue;
|
||||
}
|
||||
pointcutParameterNames[index] = this.argumentNames[i];
|
||||
pointcutParameterTypes[index] = methodParameterTypes[i];
|
||||
index++;
|
||||
}
|
||||
|
||||
this.pointcut.setParameterNames(pointcutParameterNames);
|
||||
this.pointcut.setParameterTypes(pointcutParameterTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the arguments at the method execution join point and output a set of arguments
|
||||
* to the advice method
|
||||
* @param jp the current JoinPoint
|
||||
* @param jpMatch the join point match that matched this execution join point
|
||||
* @param returnValue the return value from the method execution (may be null)
|
||||
* @param ex the exception thrown by the method execution (may be null)
|
||||
* @return the empty array if there are no arguments
|
||||
*/
|
||||
protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
|
||||
calculateArgumentBindings();
|
||||
|
||||
// AMC start
|
||||
Object[] adviceInvocationArgs = new Object[this.adviceInvocationArgumentCount];
|
||||
int numBound = 0;
|
||||
|
||||
if (this.joinPointArgumentIndex != -1) {
|
||||
adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
|
||||
numBound++;
|
||||
}
|
||||
else if (this.joinPointStaticPartArgumentIndex != -1) {
|
||||
adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
|
||||
numBound++;
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(this.argumentBindings)) {
|
||||
// binding from pointcut match
|
||||
if (jpMatch != null) {
|
||||
PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
|
||||
for (PointcutParameter parameter : parameterBindings) {
|
||||
String name = parameter.getName();
|
||||
Integer index = this.argumentBindings.get(name);
|
||||
adviceInvocationArgs[index] = parameter.getBinding();
|
||||
numBound++;
|
||||
}
|
||||
}
|
||||
// binding from returning clause
|
||||
if (this.returningName != null) {
|
||||
Integer index = this.argumentBindings.get(this.returningName);
|
||||
adviceInvocationArgs[index] = returnValue;
|
||||
numBound++;
|
||||
}
|
||||
// binding from thrown exception
|
||||
if (this.throwingName != null) {
|
||||
Integer index = this.argumentBindings.get(this.throwingName);
|
||||
adviceInvocationArgs[index] = ex;
|
||||
numBound++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numBound != this.adviceInvocationArgumentCount) {
|
||||
throw new IllegalStateException("Required to bind " + this.adviceInvocationArgumentCount
|
||||
+ " arguments, but only bound " + numBound + " (JoinPointMatch " +
|
||||
(jpMatch == null ? "was NOT" : "WAS") +
|
||||
" bound in invocation)");
|
||||
}
|
||||
|
||||
return adviceInvocationArgs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke the advice method.
|
||||
* @param jpMatch the JoinPointMatch that matched this execution join point
|
||||
* @param returnValue the return value from the method execution (may be null)
|
||||
* @param ex the exception thrown by the method execution (may be null)
|
||||
* @return the invocation result
|
||||
* @throws Throwable in case of invocation failure
|
||||
*/
|
||||
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
|
||||
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
|
||||
}
|
||||
|
||||
// As above, but in this case we are given the join point.
|
||||
protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t)
|
||||
throws Throwable {
|
||||
|
||||
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
|
||||
}
|
||||
|
||||
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
|
||||
Object[] actualArgs = args;
|
||||
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
|
||||
actualArgs = null;
|
||||
}
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
|
||||
// TODO AopUtils.invokeJoinpointUsingReflection
|
||||
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new AopInvocationException("Mismatch on arguments to advice method [" +
|
||||
this.aspectJAdviceMethod + "]; pointcut expression [" +
|
||||
this.pointcut.getPointcutExpression() + "]", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden in around advice to return proceeding join point.
|
||||
*/
|
||||
protected JoinPoint getJoinPoint() {
|
||||
return currentJoinPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current join point match at the join point we are being dispatched on.
|
||||
*/
|
||||
protected JoinPointMatch getJoinPointMatch() {
|
||||
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
|
||||
if (!(mi instanceof ProxyMethodInvocation)) {
|
||||
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
|
||||
}
|
||||
return getJoinPointMatch((ProxyMethodInvocation) mi);
|
||||
}
|
||||
|
||||
// Note: We can't use JoinPointMatch.getClass().getName() as the key, since
|
||||
// Spring AOP does all the matching at a join point, and then all the invocations.
|
||||
// Under this scenario, if we just use JoinPointMatch as the key, then
|
||||
// 'last man wins' which is not what we want at all.
|
||||
// Using the expression is guaranteed to be safe, since 2 identical expressions
|
||||
// are guaranteed to bind in exactly the same way.
|
||||
protected JoinPointMatch getJoinPointMatch(ProxyMethodInvocation pmi) {
|
||||
return (JoinPointMatch) pmi.getUserAttribute(this.pointcut.getExpression());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + ": advice method [" + this.aspectJAdviceMethod + "]; " +
|
||||
"aspect name '" + this.aspectName + "'";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MethodMatcher that excludes the specified advice method.
|
||||
* @see AbstractAspectJAdvice#buildSafePointcut()
|
||||
*/
|
||||
private static class AdviceExcludingMethodMatcher extends StaticMethodMatcher {
|
||||
|
||||
private final Method adviceMethod;
|
||||
|
||||
public AdviceExcludingMethodMatcher(Method adviceMethod) {
|
||||
this.adviceMethod = adviceMethod;
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
return !this.adviceMethod.equals(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AdviceExcludingMethodMatcher)) {
|
||||
return false;
|
||||
}
|
||||
AdviceExcludingMethodMatcher otherMm = (AdviceExcludingMethodMatcher) other;
|
||||
return this.adviceMethod.equals(otherMm.adviceMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.adviceMethod.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* Interface implemented to provide an instance of an AspectJ aspect.
|
||||
* Decouples from Spring's bean factory.
|
||||
*
|
||||
* <p>Extends the {@link org.springframework.core.Ordered} interface
|
||||
* to express an order value for the underlying aspect in a chain.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.beans.factory.BeanFactory#getBean
|
||||
*/
|
||||
public interface AspectInstanceFactory extends Ordered {
|
||||
|
||||
/**
|
||||
* Create an instance of this factory's aspect.
|
||||
* @return the aspect instance (never <code>null</code>)
|
||||
*/
|
||||
Object getAspectInstance();
|
||||
|
||||
/**
|
||||
* Expose the aspect class loader that this factory uses.
|
||||
* @return the aspect class loader (never <code>null</code>)
|
||||
*/
|
||||
ClassLoader getAspectClassLoader();
|
||||
|
||||
}
|
||||
-804
@@ -1,804 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.weaver.tools.PointcutParser;
|
||||
import org.aspectj.weaver.tools.PointcutPrimitive;
|
||||
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ParameterNameDiscoverer} implementation that tries to deduce parameter names
|
||||
* for an advice method from the pointcut expression, returning, and throwing clauses.
|
||||
* If an unambiguous interpretation is not available, it returns <code>null</code>.
|
||||
*
|
||||
* <p>This class interprets arguments in the following way:
|
||||
* <ol>
|
||||
* <li>If the first parameter of the method is of type {@link JoinPoint}
|
||||
* or {@link ProceedingJoinPoint}, it is assumed to be for passing
|
||||
* <code>thisJoinPoint</code> to the advice, and the parameter name will
|
||||
* be assigned the value <code>"thisJoinPoint"</code>.</li>
|
||||
* <li>If the first parameter of the method is of type
|
||||
* <code>JoinPoint.StaticPart</code>, it is assumed to be for passing
|
||||
* <code>"thisJoinPointStaticPart"</code> to the advice, and the parameter name
|
||||
* will be assigned the value <code>"thisJoinPointStaticPart"</code>.</li>
|
||||
* <li>If a {@link #setThrowingName(String) throwingName} has been set, and
|
||||
* there are no unbound arguments of type <code>Throwable+</code>, then an
|
||||
* {@link IllegalArgumentException} is raised. If there is more than one
|
||||
* unbound argument of type <code>Throwable+</code>, then an
|
||||
* {@link AmbiguousBindingException} is raised. If there is exactly one
|
||||
* unbound argument of type <code>Throwable+</code>, then the corresponding
|
||||
* parameter name is assigned the value <throwingName>.</li>
|
||||
* <li>If there remain unbound arguments, then the pointcut expression is
|
||||
* examined. Let <code>a</code> be the number of annotation-based pointcut
|
||||
* expressions (@annotation, @this, @target, @args,
|
||||
* @within, @withincode) that are used in binding form. Usage in
|
||||
* binding form has itself to be deduced: if the expression inside the
|
||||
* pointcut is a single string literal that meets Java variable name
|
||||
* conventions it is assumed to be a variable name. If <code>a</code> is
|
||||
* zero we proceed to the next stage. If <code>a</code> > 1 then an
|
||||
* <code>AmbiguousBindingException</code> is raised. If <code>a</code> == 1,
|
||||
* and there are no unbound arguments of type <code>Annotation+</code>,
|
||||
* then an <code>IllegalArgumentException</code> is raised. if there is
|
||||
* exactly one such argument, then the corresponding parameter name is
|
||||
* assigned the value from the pointcut expression.</li>
|
||||
* <li>If a returningName has been set, and there are no unbound arguments
|
||||
* then an <code>IllegalArgumentException</code> is raised. If there is
|
||||
* more than one unbound argument then an
|
||||
* <code>AmbiguousBindingException</code> is raised. If there is exactly
|
||||
* one unbound argument then the corresponding parameter name is assigned
|
||||
* the value <returningName>.</li>
|
||||
* <li>If there remain unbound arguments, then the pointcut expression is
|
||||
* examined once more for <code>this</code>, <code>target</code>, and
|
||||
* <code>args</code> pointcut expressions used in the binding form (binding
|
||||
* forms are deduced as described for the annotation based pointcuts). If
|
||||
* there remains more than one unbound argument of a primitive type (which
|
||||
* can only be bound in <code>args</code>) then an
|
||||
* <code>AmbiguousBindingException</code> is raised. If there is exactly
|
||||
* one argument of a primitive type, then if exactly one <code>args</code>
|
||||
* bound variable was found, we assign the corresponding parameter name
|
||||
* the variable name. If there were no <code>args</code> bound variables
|
||||
* found an <code>IllegalStateException</code> is raised. If there are
|
||||
* multiple <code>args</code> bound variables, an
|
||||
* <code>AmbiguousBindingException</code> is raised. At this point, if
|
||||
* there remains more than one unbound argument we raise an
|
||||
* <code>AmbiguousBindingException</code>. If there are no unbound arguments
|
||||
* remaining, we are done. If there is exactly one unbound argument
|
||||
* remaining, and only one candidate variable name unbound from
|
||||
* <code>this</code>, <code>target</code>, or <code>args</code>, it is
|
||||
* assigned as the corresponding parameter name. If there are multiple
|
||||
* possibilities, an <code>AmbiguousBindingException</code> is raised.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>The behavior on raising an <code>IllegalArgumentException</code> or
|
||||
* <code>AmbiguousBindingException</code> is configurable to allow this discoverer
|
||||
* to be used as part of a chain-of-responsibility. By default the condition will
|
||||
* be logged and the <code>getParameterNames(..)</code> method will simply return
|
||||
* <code>null</code>. If the {@link #setRaiseExceptions(boolean) raiseExceptions}
|
||||
* property is set to <code>true</code>, the conditions will be thrown as
|
||||
* <code>IllegalArgumentException</code> and <code>AmbiguousBindingException</code>,
|
||||
* respectively.
|
||||
*
|
||||
* <p>Was that perfectly clear? ;)
|
||||
*
|
||||
* <p>Short version: If an unambiguous binding can be deduced, then it is.
|
||||
* If the advice requirements cannot possibly be satisfied, then <code>null</code>
|
||||
* is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions}
|
||||
* property to <code>true</code>, descriptive exceptions will be thrown instead of
|
||||
* returning <code>null</code> in the case that the parameter names cannot be discovered.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
private static final String THIS_JOIN_POINT = "thisJoinPoint";
|
||||
private static final String THIS_JOIN_POINT_STATIC_PART = "thisJoinPointStaticPart";
|
||||
|
||||
// Steps in the binding algorithm...
|
||||
private static final int STEP_JOIN_POINT_BINDING = 1;
|
||||
private static final int STEP_THROWING_BINDING = 2;
|
||||
private static final int STEP_ANNOTATION_BINDING = 3;
|
||||
private static final int STEP_RETURNING_BINDING = 4;
|
||||
private static final int STEP_PRIMITIVE_ARGS_BINDING = 5;
|
||||
private static final int STEP_THIS_TARGET_ARGS_BINDING = 6;
|
||||
private static final int STEP_REFERENCE_PCUT_BINDING = 7;
|
||||
private static final int STEP_FINISHED = 8;
|
||||
|
||||
private static final Set<String> singleValuedAnnotationPcds = new HashSet<String>();
|
||||
private static final Set<String> nonReferencePointcutTokens = new HashSet<String>();
|
||||
|
||||
|
||||
static {
|
||||
singleValuedAnnotationPcds.add("@this");
|
||||
singleValuedAnnotationPcds.add("@target");
|
||||
singleValuedAnnotationPcds.add("@within");
|
||||
singleValuedAnnotationPcds.add("@withincode");
|
||||
singleValuedAnnotationPcds.add("@annotation");
|
||||
|
||||
Set pointcutPrimitives = PointcutParser.getAllSupportedPointcutPrimitives();
|
||||
for (Iterator iterator = pointcutPrimitives.iterator(); iterator.hasNext();) {
|
||||
PointcutPrimitive primitive = (PointcutPrimitive) iterator.next();
|
||||
nonReferencePointcutTokens.add(primitive.getName());
|
||||
}
|
||||
nonReferencePointcutTokens.add("&&");
|
||||
nonReferencePointcutTokens.add("!");
|
||||
nonReferencePointcutTokens.add("||");
|
||||
nonReferencePointcutTokens.add("and");
|
||||
nonReferencePointcutTokens.add("or");
|
||||
nonReferencePointcutTokens.add("not");
|
||||
}
|
||||
|
||||
|
||||
private boolean raiseExceptions;
|
||||
|
||||
/**
|
||||
* If the advice is afterReturning, and binds the return value, this is the parameter name used.
|
||||
*/
|
||||
private String returningName;
|
||||
|
||||
/**
|
||||
* If the advice is afterThrowing, and binds the thrown value, this is the parameter name used.
|
||||
*/
|
||||
private String throwingName;
|
||||
|
||||
/**
|
||||
* The pointcut expression associated with the advice, as a simple String.
|
||||
*/
|
||||
private String pointcutExpression;
|
||||
|
||||
private Class[] argumentTypes;
|
||||
|
||||
private String[] parameterNameBindings;
|
||||
|
||||
private int numberOfRemainingUnboundArguments;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new discoverer that attempts to discover parameter names
|
||||
* from the given pointcut expression.
|
||||
*/
|
||||
public AspectJAdviceParameterNameDiscoverer(String pointcutExpression) {
|
||||
this.pointcutExpression = pointcutExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether {@link IllegalArgumentException} and {@link AmbiguousBindingException}
|
||||
* must be thrown as appropriate in the case of failing to deduce advice parameter names.
|
||||
* @param raiseExceptions <code>true</code> if exceptions are to be thrown
|
||||
*/
|
||||
public void setRaiseExceptions(boolean raiseExceptions) {
|
||||
this.raiseExceptions = raiseExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* If <code>afterReturning</code> advice binds the return value, the
|
||||
* returning variable name must be specified.
|
||||
* @param returningName the name of the returning variable
|
||||
*/
|
||||
public void setReturningName(String returningName) {
|
||||
this.returningName = returningName;
|
||||
}
|
||||
|
||||
/**
|
||||
* If <code>afterThrowing</code> advice binds the thrown value, the
|
||||
* throwing variable name must be specified.
|
||||
* @param throwingName the name of the throwing variable
|
||||
*/
|
||||
public void setThrowingName(String throwingName) {
|
||||
this.throwingName = throwingName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deduce the parameter names for an advice method.
|
||||
* <p>See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc}
|
||||
* for this class for details of the algorithm used.
|
||||
* @param method the target {@link Method}
|
||||
* @return the parameter names
|
||||
*/
|
||||
public String[] getParameterNames(Method method) {
|
||||
this.argumentTypes = method.getParameterTypes();
|
||||
this.numberOfRemainingUnboundArguments = this.argumentTypes.length;
|
||||
this.parameterNameBindings = new String[this.numberOfRemainingUnboundArguments];
|
||||
|
||||
int minimumNumberUnboundArgs = 0;
|
||||
if (this.returningName != null) {
|
||||
minimumNumberUnboundArgs++;
|
||||
}
|
||||
if (this.throwingName != null) {
|
||||
minimumNumberUnboundArgs++;
|
||||
}
|
||||
if (this.numberOfRemainingUnboundArguments < minimumNumberUnboundArgs) {
|
||||
throw new IllegalStateException(
|
||||
"Not enough arguments in method to satisfy binding of returning and throwing variables");
|
||||
}
|
||||
|
||||
try {
|
||||
int algorithmicStep = STEP_JOIN_POINT_BINDING;
|
||||
while ((this.numberOfRemainingUnboundArguments > 0) && algorithmicStep < STEP_FINISHED) {
|
||||
switch (algorithmicStep++) {
|
||||
case STEP_JOIN_POINT_BINDING:
|
||||
if (!maybeBindThisJoinPoint()) {
|
||||
maybeBindThisJoinPointStaticPart();
|
||||
}
|
||||
break;
|
||||
case STEP_THROWING_BINDING:
|
||||
maybeBindThrowingVariable();
|
||||
break;
|
||||
case STEP_ANNOTATION_BINDING:
|
||||
maybeBindAnnotationsFromPointcutExpression();
|
||||
break;
|
||||
case STEP_RETURNING_BINDING:
|
||||
maybeBindReturningVariable();
|
||||
break;
|
||||
case STEP_PRIMITIVE_ARGS_BINDING:
|
||||
maybeBindPrimitiveArgsFromPointcutExpression();
|
||||
break;
|
||||
case STEP_THIS_TARGET_ARGS_BINDING:
|
||||
maybeBindThisOrTargetOrArgsFromPointcutExpression();
|
||||
break;
|
||||
case STEP_REFERENCE_PCUT_BINDING:
|
||||
maybeBindReferencePointcutParameter();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown algorithmic step: " + (algorithmicStep - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AmbiguousBindingException ambigEx) {
|
||||
if (this.raiseExceptions) {
|
||||
throw ambigEx;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
if (this.raiseExceptions) {
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.numberOfRemainingUnboundArguments == 0) {
|
||||
return this.parameterNameBindings;
|
||||
}
|
||||
else {
|
||||
if (this.raiseExceptions) {
|
||||
throw new IllegalStateException("Failed to bind all argument names: " +
|
||||
this.numberOfRemainingUnboundArguments + " argument(s) could not be bound");
|
||||
}
|
||||
else {
|
||||
// convention for failing is to return null, allowing participation in a chain of responsibility
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An advice method can never be a constructor in Spring.
|
||||
* @return <code>null</code>
|
||||
* @throws UnsupportedOperationException if
|
||||
* {@link #setRaiseExceptions(boolean) raiseExceptions} has been set to <code>true</code>
|
||||
*/
|
||||
public String[] getParameterNames(Constructor ctor) {
|
||||
if (this.raiseExceptions) {
|
||||
throw new UnsupportedOperationException("An advice method can never be a constructor");
|
||||
}
|
||||
else {
|
||||
// we return null rather than throw an exception so that we behave well
|
||||
// in a chain-of-responsibility.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void bindParameterName(int index, String name) {
|
||||
this.parameterNameBindings[index] = name;
|
||||
this.numberOfRemainingUnboundArguments--;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the first parameter is of type JoinPoint or ProceedingJoinPoint,bind "thisJoinPoint" as
|
||||
* parameter name and return true, else return false.
|
||||
*/
|
||||
private boolean maybeBindThisJoinPoint() {
|
||||
if ((this.argumentTypes[0] == JoinPoint.class) || (this.argumentTypes[0] == ProceedingJoinPoint.class)) {
|
||||
bindParameterName(0, THIS_JOIN_POINT);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeBindThisJoinPointStaticPart() {
|
||||
if (this.argumentTypes[0] == JoinPoint.StaticPart.class) {
|
||||
bindParameterName(0, THIS_JOIN_POINT_STATIC_PART);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a throwing name was specified and there is exactly one choice remaining
|
||||
* (argument that is a subtype of Throwable) then bind it.
|
||||
*/
|
||||
private void maybeBindThrowingVariable() {
|
||||
if (this.throwingName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// So there is binding work to do...
|
||||
int throwableIndex = -1;
|
||||
for (int i = 0; i < this.argumentTypes.length; i++) {
|
||||
if (isUnbound(i) && isSubtypeOf(Throwable.class, i)) {
|
||||
if (throwableIndex == -1) {
|
||||
throwableIndex = i;
|
||||
}
|
||||
else {
|
||||
// Second candidate we've found - ambiguous binding
|
||||
throw new AmbiguousBindingException("Binding of throwing parameter '" +
|
||||
this.throwingName + "' is ambiguous: could be bound to argument " +
|
||||
throwableIndex + " or argument " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (throwableIndex == -1) {
|
||||
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName
|
||||
+ "' could not be completed as no available arguments are a subtype of Throwable");
|
||||
}
|
||||
else {
|
||||
bindParameterName(throwableIndex, this.throwingName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a returning variable was specified and there is only one choice remaining, bind it.
|
||||
*/
|
||||
private void maybeBindReturningVariable() {
|
||||
if (this.numberOfRemainingUnboundArguments == 0) {
|
||||
throw new IllegalStateException(
|
||||
"Algorithm assumes that there must be at least one unbound parameter on entry to this method");
|
||||
}
|
||||
|
||||
if (this.returningName != null) {
|
||||
if (this.numberOfRemainingUnboundArguments > 1) {
|
||||
throw new AmbiguousBindingException("Binding of returning parameter '" + this.returningName +
|
||||
"' is ambiguous, there are " + this.numberOfRemainingUnboundArguments + " candidates.");
|
||||
}
|
||||
|
||||
// We're all set... find the unbound parameter, and bind it.
|
||||
for (int i = 0; i < this.parameterNameBindings.length; i++) {
|
||||
if (this.parameterNameBindings[i] == null) {
|
||||
bindParameterName(i, this.returningName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the string pointcut expression looking for:
|
||||
* @this, @target, @args, @within, @withincode, @annotation.
|
||||
* If we find one of these pointcut expressions, try and extract a candidate variable
|
||||
* name (or variable names, in the case of args).
|
||||
* <p>Some more support from AspectJ in doing this exercise would be nice... :)
|
||||
*/
|
||||
private void maybeBindAnnotationsFromPointcutExpression() {
|
||||
List<String> varNames = new ArrayList<String>();
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String toMatch = tokens[i];
|
||||
int firstParenIndex = toMatch.indexOf("(");
|
||||
if (firstParenIndex != -1) {
|
||||
toMatch = toMatch.substring(0, firstParenIndex);
|
||||
}
|
||||
if (singleValuedAnnotationPcds.contains(toMatch)) {
|
||||
PointcutBody body = getPointcutBody(tokens, i);
|
||||
i += body.numTokensConsumed;
|
||||
String varName = maybeExtractVariableName(body.text);
|
||||
if (varName != null) {
|
||||
varNames.add(varName);
|
||||
}
|
||||
}
|
||||
else if (tokens[i].startsWith("@args(") || tokens[i].equals("@args")) {
|
||||
PointcutBody body = getPointcutBody(tokens, i);
|
||||
i += body.numTokensConsumed;
|
||||
maybeExtractVariableNamesFromArgs(body.text, varNames);
|
||||
}
|
||||
}
|
||||
|
||||
bindAnnotationsFromVarNames(varNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the given list of extracted variable names to argument slots.
|
||||
*/
|
||||
private void bindAnnotationsFromVarNames(List<String> varNames) {
|
||||
if (!varNames.isEmpty()) {
|
||||
// we have work to do...
|
||||
int numAnnotationSlots = countNumberOfUnboundAnnotationArguments();
|
||||
if (numAnnotationSlots > 1) {
|
||||
throw new AmbiguousBindingException("Found " + varNames.size() +
|
||||
" potential annotation variable(s), and " +
|
||||
numAnnotationSlots + " potential argument slots");
|
||||
}
|
||||
else if (numAnnotationSlots == 1) {
|
||||
if (varNames.size() == 1) {
|
||||
// it's a match
|
||||
findAndBind(Annotation.class, varNames.get(0));
|
||||
}
|
||||
else {
|
||||
// multiple candidate vars, but only one slot
|
||||
throw new IllegalArgumentException("Found " + varNames.size() +
|
||||
" candidate annotation binding variables" +
|
||||
" but only one potential argument binding slot");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no slots so presume those candidate vars were actually type names
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the token starts meets Java identifier conventions, it's in.
|
||||
*/
|
||||
private String maybeExtractVariableName(String candidateToken) {
|
||||
if (candidateToken == null || candidateToken.equals("")) {
|
||||
return null;
|
||||
}
|
||||
if (Character.isJavaIdentifierStart(candidateToken.charAt(0)) &&
|
||||
Character.isLowerCase(candidateToken.charAt(0))) {
|
||||
char[] tokenChars = candidateToken.toCharArray();
|
||||
for (char tokenChar : tokenChars) {
|
||||
if (!Character.isJavaIdentifierPart(tokenChar)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return candidateToken;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an args pointcut body (could be <code>args</code> or <code>at_args</code>),
|
||||
* add any candidate variable names to the given list.
|
||||
*/
|
||||
private void maybeExtractVariableNamesFromArgs(String argsSpec, List<String> varNames) {
|
||||
if (argsSpec == null) {
|
||||
return;
|
||||
}
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(argsSpec, ",");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
tokens[i] = StringUtils.trimWhitespace(tokens[i]);
|
||||
String varName = maybeExtractVariableName(tokens[i]);
|
||||
if (varName != null) {
|
||||
varNames.add(varName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string pointcut expression looking for this(), target() and args() expressions.
|
||||
* If we find one, try and extract a candidate variable name and bind it.
|
||||
*/
|
||||
private void maybeBindThisOrTargetOrArgsFromPointcutExpression() {
|
||||
if (this.numberOfRemainingUnboundArguments > 1) {
|
||||
throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments
|
||||
+ " unbound args at this(),target(),args() binding stage, with no way to determine between them");
|
||||
}
|
||||
|
||||
List<String> varNames = new ArrayList<String>();
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
if (tokens[i].equals("this") ||
|
||||
tokens[i].startsWith("this(") ||
|
||||
tokens[i].equals("target") ||
|
||||
tokens[i].startsWith("target(")) {
|
||||
PointcutBody body = getPointcutBody(tokens, i);
|
||||
i += body.numTokensConsumed;
|
||||
String varName = maybeExtractVariableName(body.text);
|
||||
if (varName != null) {
|
||||
varNames.add(varName);
|
||||
}
|
||||
}
|
||||
else if (tokens[i].equals("args") || tokens[i].startsWith("args(")) {
|
||||
PointcutBody body = getPointcutBody(tokens, i);
|
||||
i += body.numTokensConsumed;
|
||||
List<String> candidateVarNames = new ArrayList<String>();
|
||||
maybeExtractVariableNamesFromArgs(body.text, candidateVarNames);
|
||||
// we may have found some var names that were bound in previous primitive args binding step,
|
||||
// filter them out...
|
||||
for (String varName : candidateVarNames) {
|
||||
if (!alreadyBound(varName)) {
|
||||
varNames.add(varName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (varNames.size() > 1) {
|
||||
throw new AmbiguousBindingException("Found " + varNames.size() +
|
||||
" candidate this(), target() or args() variables but only one unbound argument slot");
|
||||
}
|
||||
else if (varNames.size() == 1) {
|
||||
for (int j = 0; j < this.parameterNameBindings.length; j++) {
|
||||
if (isUnbound(j)) {
|
||||
bindParameterName(j, varNames.get(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else varNames.size must be 0 and we have nothing to bind.
|
||||
}
|
||||
|
||||
private void maybeBindReferencePointcutParameter() {
|
||||
if (this.numberOfRemainingUnboundArguments > 1) {
|
||||
throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments
|
||||
+ " unbound args at reference pointcut binding stage, with no way to determine between them");
|
||||
}
|
||||
|
||||
List<String> varNames = new ArrayList<String>();
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
String toMatch = tokens[i];
|
||||
if (toMatch.startsWith("!")) {
|
||||
toMatch = toMatch.substring(1);
|
||||
}
|
||||
int firstParenIndex = toMatch.indexOf("(");
|
||||
if (firstParenIndex != -1) {
|
||||
toMatch = toMatch.substring(0, firstParenIndex);
|
||||
}
|
||||
else {
|
||||
if (tokens.length < i + 2) {
|
||||
// no "(" and nothing following
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
String nextToken = tokens[i + 1];
|
||||
if (nextToken.charAt(0) != '(') {
|
||||
// next token is not "(" either, can't be a pc...
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eat the body
|
||||
PointcutBody body = getPointcutBody(tokens, i);
|
||||
i += body.numTokensConsumed;
|
||||
|
||||
if (!nonReferencePointcutTokens.contains(toMatch)) {
|
||||
// then it could be a reference pointcut
|
||||
String varName = maybeExtractVariableName(body.text);
|
||||
if (varName != null) {
|
||||
varNames.add(varName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (varNames.size() > 1) {
|
||||
throw new AmbiguousBindingException("Found " + varNames.size() +
|
||||
" candidate reference pointcut variables but only one unbound argument slot");
|
||||
}
|
||||
else if (varNames.size() == 1) {
|
||||
for (int j = 0; j < this.parameterNameBindings.length; j++) {
|
||||
if (isUnbound(j)) {
|
||||
bindParameterName(j, varNames.get(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else varNames.size must be 0 and we have nothing to bind.
|
||||
}
|
||||
|
||||
/*
|
||||
* We've found the start of a binding pointcut at the given index into the
|
||||
* token array. Now we need to extract the pointcut body and return it.
|
||||
*/
|
||||
private PointcutBody getPointcutBody(String[] tokens, int startIndex) {
|
||||
int numTokensConsumed = 0;
|
||||
String currentToken = tokens[startIndex];
|
||||
int bodyStart = currentToken.indexOf('(');
|
||||
if (currentToken.charAt(currentToken.length() - 1) == ')') {
|
||||
// It's an all in one... get the text between the first (and the last)
|
||||
return new PointcutBody(0, currentToken.substring(bodyStart + 1, currentToken.length() - 1));
|
||||
}
|
||||
else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (bodyStart >= 0 && bodyStart != (currentToken.length() - 1)) {
|
||||
sb.append(currentToken.substring(bodyStart + 1));
|
||||
sb.append(" ");
|
||||
}
|
||||
numTokensConsumed++;
|
||||
int currentIndex = startIndex + numTokensConsumed;
|
||||
while (currentIndex < tokens.length) {
|
||||
if (tokens[currentIndex].equals("(")) {
|
||||
currentIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tokens[currentIndex].endsWith(")")) {
|
||||
sb.append(tokens[currentIndex].substring(0, tokens[currentIndex].length() - 1));
|
||||
return new PointcutBody(numTokensConsumed, sb.toString().trim());
|
||||
}
|
||||
|
||||
String toAppend = tokens[currentIndex];
|
||||
if (toAppend.startsWith("(")) {
|
||||
toAppend = toAppend.substring(1);
|
||||
}
|
||||
sb.append(toAppend);
|
||||
sb.append(" ");
|
||||
currentIndex++;
|
||||
numTokensConsumed++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We looked and failed...
|
||||
return new PointcutBody(numTokensConsumed, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match up args against unbound arguments of primitive types
|
||||
*/
|
||||
private void maybeBindPrimitiveArgsFromPointcutExpression() {
|
||||
int numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments();
|
||||
if (numUnboundPrimitives > 1) {
|
||||
throw new AmbiguousBindingException("Found '" + numUnboundPrimitives +
|
||||
"' unbound primitive arguments with no way to distinguish between them.");
|
||||
}
|
||||
if (numUnboundPrimitives == 1) {
|
||||
// Look for arg variable and bind it if we find exactly one...
|
||||
List<String> varNames = new ArrayList<String>();
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(this.pointcutExpression, " ");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
if (tokens[i].equals("args") || tokens[i].startsWith("args(")) {
|
||||
PointcutBody body = getPointcutBody(tokens, i);
|
||||
i += body.numTokensConsumed;
|
||||
maybeExtractVariableNamesFromArgs(body.text, varNames);
|
||||
}
|
||||
}
|
||||
if (varNames.size() > 1) {
|
||||
throw new AmbiguousBindingException("Found " + varNames.size() +
|
||||
" candidate variable names but only one candidate binding slot when matching primitive args");
|
||||
}
|
||||
else if (varNames.size() == 1) {
|
||||
// 1 primitive arg, and one candidate...
|
||||
for (int i = 0; i < this.argumentTypes.length; i++) {
|
||||
if (isUnbound(i) && this.argumentTypes[i].isPrimitive()) {
|
||||
bindParameterName(i, (String) varNames.get(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the parameter name binding for the given parameter
|
||||
* index has not yet been assigned.
|
||||
*/
|
||||
private boolean isUnbound(int i) {
|
||||
return this.parameterNameBindings[i] == null;
|
||||
}
|
||||
|
||||
private boolean alreadyBound(String varName) {
|
||||
for (int i = 0; i < this.parameterNameBindings.length; i++) {
|
||||
if (!isUnbound(i) && varName.equals(this.parameterNameBindings[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return <code>true</code> if the given argument type is a subclass
|
||||
* of the given supertype.
|
||||
*/
|
||||
private boolean isSubtypeOf(Class supertype, int argumentNumber) {
|
||||
return supertype.isAssignableFrom(this.argumentTypes[argumentNumber]);
|
||||
}
|
||||
|
||||
private int countNumberOfUnboundAnnotationArguments() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < this.argumentTypes.length; i++) {
|
||||
if (isUnbound(i) && isSubtypeOf(Annotation.class, i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int countNumberOfUnboundPrimitiveArguments() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < this.argumentTypes.length; i++) {
|
||||
if (isUnbound(i) && this.argumentTypes[i].isPrimitive()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the argument index with the given type, and bind the given
|
||||
* <code>varName</code> in that position.
|
||||
*/
|
||||
private void findAndBind(Class argumentType, String varName) {
|
||||
for (int i = 0; i < this.argumentTypes.length; i++) {
|
||||
if (isUnbound(i) && isSubtypeOf(argumentType, i)) {
|
||||
bindParameterName(i, varName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Expected to find an unbound argument of type '" +
|
||||
argumentType.getName() + "'");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple struct to hold the extracted text from a pointcut body, together
|
||||
* with the number of tokens consumed in extracting it.
|
||||
*/
|
||||
private static class PointcutBody {
|
||||
|
||||
private int numTokensConsumed;
|
||||
|
||||
private String text;
|
||||
|
||||
public PointcutBody(int tokens, String text) {
|
||||
this.numTokensConsumed = tokens;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown in response to an ambiguous binding being detected when
|
||||
* trying to resolve a method's parameter names.
|
||||
*/
|
||||
public static class AmbiguousBindingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Construct a new AmbiguousBindingException with the specified message.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AmbiguousBindingException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.AfterAdvice;
|
||||
|
||||
/**
|
||||
* Spring AOP advice wrapping an AspectJ after advice method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {
|
||||
|
||||
public AspectJAfterAdvice(
|
||||
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
|
||||
|
||||
super(aspectJBeforeAdviceMethod, pointcut, aif);
|
||||
}
|
||||
|
||||
public Object invoke(MethodInvocation mi) throws Throwable {
|
||||
try {
|
||||
return mi.proceed();
|
||||
}
|
||||
finally {
|
||||
invokeAdviceMethod(getJoinPointMatch(), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBeforeAdvice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAfterAdvice() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.springframework.aop.AfterAdvice;
|
||||
import org.springframework.aop.AfterReturningAdvice;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* Spring AOP advice wrapping an AspectJ after-returning advice method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implements AfterReturningAdvice, AfterAdvice {
|
||||
|
||||
public AspectJAfterReturningAdvice(
|
||||
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
|
||||
|
||||
super(aspectJBeforeAdviceMethod, pointcut, aif);
|
||||
}
|
||||
|
||||
public boolean isBeforeAdvice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAfterAdvice() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReturningName(String name) {
|
||||
setReturningNameNoCheck(name);
|
||||
}
|
||||
|
||||
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
|
||||
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
|
||||
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Following AspectJ semantics, if a returning clause was specified, then the
|
||||
* advice is only invoked if the returned value is an instance of the given
|
||||
* returning type and generic type parameters, if any, match the assignment
|
||||
* rules. If the returning type is Object, the advice is *always* invoked.
|
||||
* @param returnValue the return value of the target method
|
||||
* @return whether to invoke the advice method for the given return value
|
||||
*/
|
||||
private boolean shouldInvokeOnReturnValueOf(Method method, Object returnValue) {
|
||||
Class type = getDiscoveredReturningType();
|
||||
Type genericType = getDiscoveredReturningGenericType();
|
||||
// If we aren't dealing with a raw type, check if generic parameters are assignable.
|
||||
return (ClassUtils.isAssignableValue(type, returnValue) &&
|
||||
(genericType == null || genericType == type ||
|
||||
TypeUtils.isAssignable(genericType, method.getGenericReturnType())));
|
||||
}
|
||||
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.AfterAdvice;
|
||||
|
||||
/**
|
||||
* Spring AOP advice wrapping an AspectJ after-throwing advice method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {
|
||||
|
||||
public AspectJAfterThrowingAdvice(
|
||||
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
|
||||
|
||||
super(aspectJBeforeAdviceMethod, pointcut, aif);
|
||||
}
|
||||
|
||||
public boolean isBeforeAdvice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAfterAdvice() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThrowingName(String name) {
|
||||
setThrowingNameNoCheck(name);
|
||||
}
|
||||
|
||||
public Object invoke(MethodInvocation mi) throws Throwable {
|
||||
try {
|
||||
return mi.proceed();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
if (shouldInvokeOnThrowing(t)) {
|
||||
invokeAdviceMethod(getJoinPointMatch(), null, t);
|
||||
}
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In AspectJ semantics, after throwing advice that specifies a throwing clause
|
||||
* is only invoked if the thrown exception is a subtype of the given throwing type.
|
||||
*/
|
||||
private boolean shouldInvokeOnThrowing(Throwable t) {
|
||||
Class throwingType = getDiscoveredThrowingType();
|
||||
return throwingType.isAssignableFrom(t.getClass());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.AfterAdvice;
|
||||
import org.springframework.aop.BeforeAdvice;
|
||||
|
||||
/**
|
||||
* Utility methods for dealing with AspectJ advisors.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AspectJAopUtils {
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the advisor is a form of before advice.
|
||||
*/
|
||||
public static boolean isBeforeAdvice(Advisor anAdvisor) {
|
||||
AspectJPrecedenceInformation precedenceInfo = getAspectJPrecedenceInformationFor(anAdvisor);
|
||||
if (precedenceInfo != null) {
|
||||
return precedenceInfo.isBeforeAdvice();
|
||||
}
|
||||
return (anAdvisor.getAdvice() instanceof BeforeAdvice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the advisor is a form of after advice.
|
||||
*/
|
||||
public static boolean isAfterAdvice(Advisor anAdvisor) {
|
||||
AspectJPrecedenceInformation precedenceInfo = getAspectJPrecedenceInformationFor(anAdvisor);
|
||||
if (precedenceInfo != null) {
|
||||
return precedenceInfo.isAfterAdvice();
|
||||
}
|
||||
return (anAdvisor.getAdvice() instanceof AfterAdvice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AspectJPrecedenceInformation provided by this advisor or its advice.
|
||||
* If neither the advisor nor the advice have precedence information, this method
|
||||
* will return <code>null</code>.
|
||||
*/
|
||||
public static AspectJPrecedenceInformation getAspectJPrecedenceInformationFor(Advisor anAdvisor) {
|
||||
if (anAdvisor instanceof AspectJPrecedenceInformation) {
|
||||
return (AspectJPrecedenceInformation) anAdvisor;
|
||||
}
|
||||
Advice advice = anAdvisor.getAdvice();
|
||||
if (advice instanceof AspectJPrecedenceInformation) {
|
||||
return (AspectJPrecedenceInformation) advice;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.weaver.tools.JoinPointMatch;
|
||||
|
||||
import org.springframework.aop.ProxyMethodInvocation;
|
||||
|
||||
/**
|
||||
* Spring AOP around advice (MethodInterceptor) that wraps
|
||||
* an AspectJ advice method. Exposes ProceedingJoinPoint.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor {
|
||||
|
||||
public AspectJAroundAdvice(
|
||||
Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
|
||||
|
||||
super(aspectJAroundAdviceMethod, pointcut, aif);
|
||||
}
|
||||
|
||||
public boolean isBeforeAdvice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAfterAdvice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsProceedingJoinPoint() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(MethodInvocation mi) throws Throwable {
|
||||
if (!(mi instanceof ProxyMethodInvocation)) {
|
||||
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
|
||||
}
|
||||
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
|
||||
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
|
||||
JoinPointMatch jpm = getJoinPointMatch(pmi);
|
||||
return invokeAdviceMethod(pjp, jpm, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ProceedingJoinPoint for the current invocation,
|
||||
* instantiating it lazily if it hasn't been bound to the thread already.
|
||||
* @param rmi the current Spring AOP ReflectiveMethodInvocation,
|
||||
* which we'll use for attribute binding
|
||||
* @return the ProceedingJoinPoint to make available to advice methods
|
||||
*/
|
||||
protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
|
||||
return new MethodInvocationProceedingJoinPoint(rmi);
|
||||
}
|
||||
|
||||
}
|
||||
-641
@@ -1,641 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.weaver.BCException;
|
||||
import org.aspectj.weaver.patterns.NamePattern;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld;
|
||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ContextBasedMatcher;
|
||||
import org.aspectj.weaver.tools.FuzzyBoolean;
|
||||
import org.aspectj.weaver.tools.JoinPointMatch;
|
||||
import org.aspectj.weaver.tools.MatchingContext;
|
||||
import org.aspectj.weaver.tools.PointcutDesignatorHandler;
|
||||
import org.aspectj.weaver.tools.PointcutExpression;
|
||||
import org.aspectj.weaver.tools.PointcutParameter;
|
||||
import org.aspectj.weaver.tools.PointcutParser;
|
||||
import org.aspectj.weaver.tools.PointcutPrimitive;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAwareMethodMatcher;
|
||||
import org.springframework.aop.MethodMatcher;
|
||||
import org.springframework.aop.ProxyMethodInvocation;
|
||||
import org.springframework.aop.framework.autoproxy.ProxyCreationContext;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.aop.support.AbstractExpressionPointcut;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring {@link org.springframework.aop.Pointcut} implementation
|
||||
* that uses the AspectJ weaver to evaluate a pointcut expression.
|
||||
*
|
||||
* <p>The pointcut expression value is an AspectJ expression. This can
|
||||
* reference other pointcuts and use composition and other operations.
|
||||
*
|
||||
* <p>Naturally, as this is to be processed by Spring AOP's proxy-based model,
|
||||
* only method execution pointcuts are supported.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Adrian Colyer
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @author Dave Syer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
||||
implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
|
||||
|
||||
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();
|
||||
|
||||
static {
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
|
||||
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
|
||||
}
|
||||
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
|
||||
|
||||
private Class pointcutDeclarationScope;
|
||||
|
||||
private String[] pointcutParameterNames = new String[0];
|
||||
|
||||
private Class[] pointcutParameterTypes = new Class[0];
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private transient PointcutExpression pointcutExpression;
|
||||
|
||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new default AspectJExpressionPointcut.
|
||||
*/
|
||||
public AspectJExpressionPointcut() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AspectJExpressionPointcut with the given settings.
|
||||
* @param declarationScope the declaration scope for the pointcut
|
||||
* @param paramNames the parameter names for the pointcut
|
||||
* @param paramTypes the parameter types for the pointcut
|
||||
*/
|
||||
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
|
||||
this.pointcutDeclarationScope = declarationScope;
|
||||
if (paramNames.length != paramTypes.length) {
|
||||
throw new IllegalStateException(
|
||||
"Number of pointcut parameter names must match number of pointcut parameter types");
|
||||
}
|
||||
this.pointcutParameterNames = paramNames;
|
||||
this.pointcutParameterTypes = paramTypes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the declaration scope for the pointcut.
|
||||
*/
|
||||
public void setPointcutDeclarationScope(Class pointcutDeclarationScope) {
|
||||
this.pointcutDeclarationScope = pointcutDeclarationScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter names for the pointcut.
|
||||
*/
|
||||
public void setParameterNames(String[] names) {
|
||||
this.pointcutParameterNames = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameter types for the pointcut.
|
||||
*/
|
||||
public void setParameterTypes(Class[] types) {
|
||||
this.pointcutParameterTypes = types;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
|
||||
public ClassFilter getClassFilter() {
|
||||
checkReadyToMatch();
|
||||
return this;
|
||||
}
|
||||
|
||||
public MethodMatcher getMethodMatcher() {
|
||||
checkReadyToMatch();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether this pointcut is ready to match,
|
||||
* lazily building the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private void checkReadyToMatch() {
|
||||
if (getExpression() == null) {
|
||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||
}
|
||||
if (this.pointcutExpression == null) {
|
||||
this.pointcutExpression = buildPointcutExpression();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression() {
|
||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory)
|
||||
.getBeanClassLoader() : Thread.currentThread()
|
||||
.getContextClassLoader());
|
||||
return buildPointcutExpression(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
private PointcutExpression buildPointcutExpression(ClassLoader classLoader) {
|
||||
PointcutParser parser = initializePointcutParser(classLoader);
|
||||
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
|
||||
for (int i = 0; i < pointcutParameters.length; i++) {
|
||||
pointcutParameters[i] = parser.createPointcutParameter(
|
||||
this.pointcutParameterNames[i],
|
||||
this.pointcutParameterTypes[i]);
|
||||
}
|
||||
return parser.parsePointcutExpression(
|
||||
replaceBooleanOperators(getExpression()),
|
||||
this.pointcutDeclarationScope, pointcutParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the underlying AspectJ pointcut parser.
|
||||
*/
|
||||
private PointcutParser initializePointcutParser(ClassLoader cl) {
|
||||
PointcutParser parser = PointcutParser
|
||||
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
|
||||
SUPPORTED_PRIMITIVES, cl);
|
||||
parser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
|
||||
return parser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If a pointcut expression has been specified in XML, the user cannot
|
||||
* write <code>and</code> as "&&" (though && will work).
|
||||
* We also allow <code>and</code> between two pointcut sub-expressions.
|
||||
* <p>This method converts back to <code>&&</code> for the AspectJ pointcut parser.
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
String result = StringUtils.replace(pcExpr, " and ", " && ");
|
||||
result = StringUtils.replace(result, " or ", " || ");
|
||||
result = StringUtils.replace(result, " not ", " ! ");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the underlying AspectJ pointcut expression.
|
||||
*/
|
||||
public PointcutExpression getPointcutExpression() {
|
||||
checkReadyToMatch();
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
public boolean matches(Class targetClass) {
|
||||
checkReadyToMatch();
|
||||
try {
|
||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||
} catch (ReflectionWorldException e) {
|
||||
logger.debug("PointcutExpression matching rejected target class", e);
|
||||
try {
|
||||
// Actually this is still a "maybe" - treat the pointcut as dynamic if we
|
||||
// don't know enough yet
|
||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
||||
} catch (BCException ex) {
|
||||
logger.debug(
|
||||
"Fallback PointcutExpression matching rejected target class",
|
||||
ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (BCException ex) {
|
||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, boolean beanHasIntroductions) {
|
||||
checkReadyToMatch();
|
||||
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
|
||||
|
||||
// Special handling for this, target, @this, @target, @annotation
|
||||
// in Spring - we can optimize since we know we have exactly this class,
|
||||
// and there will never be matching subclass at runtime.
|
||||
if (shadowMatch.alwaysMatches()) {
|
||||
return true;
|
||||
}
|
||||
else if (shadowMatch.neverMatches()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// the maybe case
|
||||
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
return matches(method, targetClass, false);
|
||||
}
|
||||
|
||||
public boolean isRuntime() {
|
||||
checkReadyToMatch();
|
||||
return this.pointcutExpression.mayNeedDynamicTest();
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
checkReadyToMatch();
|
||||
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
|
||||
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
|
||||
|
||||
// Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
|
||||
// consistent with return of MethodInvocationProceedingJoinPoint
|
||||
ProxyMethodInvocation pmi = null;
|
||||
Object targetObject = null;
|
||||
Object thisObject = null;
|
||||
try {
|
||||
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
|
||||
targetObject = mi.getThis();
|
||||
if (!(mi instanceof ProxyMethodInvocation)) {
|
||||
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
|
||||
}
|
||||
pmi = (ProxyMethodInvocation) mi;
|
||||
thisObject = pmi.getProxy();
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// No current invocation...
|
||||
// TODO: Should we really proceed here?
|
||||
logger.debug("Couldn't access current invocation - matching with limited context: " + ex);
|
||||
}
|
||||
|
||||
JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
|
||||
|
||||
/*
|
||||
* Do a final check to see if any this(TYPE) kind of residue match. For
|
||||
* this purpose, we use the original method's (proxy method's) shadow to
|
||||
* ensure that 'this' is correctly checked against. Without this check,
|
||||
* we get incorrect match on this(TYPE) where TYPE matches the target
|
||||
* type but not 'this' (as would be the case of JDK dynamic proxies).
|
||||
* <p>See SPR-2979 for the original bug.
|
||||
*/
|
||||
if (pmi != null) { // there is a current invocation
|
||||
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (joinPointMatch.matches() && pmi != null) {
|
||||
bindParameters(pmi, joinPointMatch);
|
||||
}
|
||||
return joinPointMatch.matches();
|
||||
}
|
||||
|
||||
|
||||
protected String getCurrentProxiedBeanName() {
|
||||
return ProxyCreationContext.getCurrentProxiedBeanName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a new pointcut expression based on a target class's loader, rather
|
||||
* than the default.
|
||||
*/
|
||||
private PointcutExpression getFallbackPointcutExpression(
|
||||
Class<?> targetClass) {
|
||||
ClassLoader classLoader = targetClass.getClassLoader();
|
||||
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* A match test returned maybe - if there are any subtype sensitive variables
|
||||
* involved in the test (this, target, at_this, at_target, at_annotation) then
|
||||
* we say this is not a match as in Spring there will never be a different
|
||||
* runtime subtype.
|
||||
*/
|
||||
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
|
||||
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
|
||||
}
|
||||
|
||||
private boolean matchesTarget(ShadowMatch shadowMatch, Class targetClass) {
|
||||
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
|
||||
}
|
||||
|
||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
if (shadowMatch instanceof DefensiveShadowMatch) {
|
||||
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary);
|
||||
}
|
||||
return new RuntimeTestWalker(shadowMatch);
|
||||
}
|
||||
|
||||
private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm) {
|
||||
// Note: Can't use JoinPointMatch.getClass().getName() as the key, since
|
||||
// Spring AOP does all the matching at a join point, and then all the invocations
|
||||
// under this scenario, if we just use JoinPointMatch as the key, then
|
||||
// 'last man wins' which is not what we want at all.
|
||||
// Using the expression is guaranteed to be safe, since 2 identical expressions
|
||||
// are guaranteed to bind in exactly the same way.
|
||||
invocation.setUserAttribute(getExpression(), jpm);
|
||||
}
|
||||
|
||||
private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
|
||||
// Avoid lock contention for known Methods through concurrent access...
|
||||
ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
synchronized (this.shadowMatchCache) {
|
||||
// Not found - now check again with full lock...
|
||||
Method methodToMatch = targetMethod;
|
||||
PointcutExpression fallbackPointcutExpression = null;
|
||||
shadowMatch = this.shadowMatchCache.get(methodToMatch);
|
||||
if (shadowMatch == null) {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex) {
|
||||
// Failed to introspect target method, probably because it has been loaded
|
||||
// in a special ClassLoader. Let's try the original method instead...
|
||||
try {
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e) {
|
||||
if (targetMethod == originalMethod) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
||||
}
|
||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's simply consider this method as non-matching.
|
||||
methodToMatch = originalMethod;
|
||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||
try {
|
||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
||||
} catch (ReflectionWorld.ReflectionWorldException e2) {
|
||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) {
|
||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
||||
}
|
||||
this.shadowMatchCache.put(targetMethod, shadowMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return shadowMatch;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AspectJExpressionPointcut)) {
|
||||
return false;
|
||||
}
|
||||
AspectJExpressionPointcut otherPc = (AspectJExpressionPointcut) other;
|
||||
return ObjectUtils.nullSafeEquals(this.getExpression(), otherPc.getExpression()) &&
|
||||
ObjectUtils.nullSafeEquals(this.pointcutDeclarationScope, otherPc.pointcutDeclarationScope) &&
|
||||
ObjectUtils.nullSafeEquals(this.pointcutParameterNames, otherPc.pointcutParameterNames) &&
|
||||
ObjectUtils.nullSafeEquals(this.pointcutParameterTypes, otherPc.pointcutParameterTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = ObjectUtils.nullSafeHashCode(this.getExpression());
|
||||
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutDeclarationScope);
|
||||
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterNames);
|
||||
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterTypes);
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("AspectJExpressionPointcut: ");
|
||||
if (this.pointcutParameterNames != null && this.pointcutParameterTypes != null) {
|
||||
sb.append("(");
|
||||
for (int i = 0; i < this.pointcutParameterTypes.length; i++) {
|
||||
sb.append(this.pointcutParameterTypes[i].getName());
|
||||
sb.append(" ");
|
||||
sb.append(this.pointcutParameterNames[i]);
|
||||
if ((i+1) < this.pointcutParameterTypes.length) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(" ");
|
||||
if (getExpression() != null) {
|
||||
sb.append(getExpression());
|
||||
}
|
||||
else {
|
||||
sb.append("<pointcut expression not set>");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for the Spring-specific <code>bean()</code> pointcut designator
|
||||
* extension to AspectJ.
|
||||
* <p>This handler must be added to each pointcut object that needs to
|
||||
* handle the <code>bean()</code> PCD. Matching context is obtained
|
||||
* automatically by examining a thread local variable and therefore a matching
|
||||
* context need not be set on the pointcut.
|
||||
*/
|
||||
private class BeanNamePointcutDesignatorHandler implements PointcutDesignatorHandler {
|
||||
|
||||
private static final String BEAN_DESIGNATOR_NAME = "bean";
|
||||
|
||||
public String getDesignatorName() {
|
||||
return BEAN_DESIGNATOR_NAME;
|
||||
}
|
||||
|
||||
public ContextBasedMatcher parse(String expression) {
|
||||
return new BeanNameContextMatcher(expression);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Matcher class for the BeanNamePointcutDesignatorHandler.
|
||||
* <p>Dynamic match tests for this matcher always return true,
|
||||
* since the matching decision is made at the proxy creation time.
|
||||
* For static match tests, this matcher abstains to allow the overall
|
||||
* pointcut to match even when negation is used with the bean() pointcut.
|
||||
*/
|
||||
private class BeanNameContextMatcher implements ContextBasedMatcher {
|
||||
|
||||
private final NamePattern expressionPattern;
|
||||
|
||||
public BeanNameContextMatcher(String expression) {
|
||||
this.expressionPattern = new NamePattern(expression);
|
||||
}
|
||||
|
||||
public boolean couldMatchJoinPointsInType(Class someClass) {
|
||||
return (contextMatch(someClass) == FuzzyBoolean.YES);
|
||||
}
|
||||
|
||||
public boolean couldMatchJoinPointsInType(Class someClass, MatchingContext context) {
|
||||
return (contextMatch(someClass) == FuzzyBoolean.YES);
|
||||
}
|
||||
|
||||
public boolean matchesDynamically(MatchingContext context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public FuzzyBoolean matchesStatically(MatchingContext context) {
|
||||
return contextMatch(null);
|
||||
}
|
||||
|
||||
public boolean mayNeedDynamicTest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private FuzzyBoolean contextMatch(Class targetType) {
|
||||
String advisedBeanName = getCurrentProxiedBeanName();
|
||||
if (advisedBeanName == null) { // no proxy creation in progress
|
||||
// abstain; can't return YES, since that will make pointcut with negation fail
|
||||
return FuzzyBoolean.MAYBE;
|
||||
}
|
||||
if (BeanFactoryUtils.isGeneratedBeanName(advisedBeanName)) {
|
||||
return FuzzyBoolean.NO;
|
||||
}
|
||||
if (targetType != null) {
|
||||
boolean isFactory = FactoryBean.class.isAssignableFrom(targetType);
|
||||
return FuzzyBoolean.fromBoolean(
|
||||
matchesBeanName(isFactory ? BeanFactory.FACTORY_BEAN_PREFIX + advisedBeanName : advisedBeanName));
|
||||
}
|
||||
else {
|
||||
return FuzzyBoolean.fromBoolean(matchesBeanName(advisedBeanName) ||
|
||||
matchesBeanName(BeanFactory.FACTORY_BEAN_PREFIX + advisedBeanName));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchesBeanName(String advisedBeanName) {
|
||||
if (this.expressionPattern.matches(advisedBeanName)) {
|
||||
return true;
|
||||
}
|
||||
if (beanFactory != null) {
|
||||
String[] aliases = beanFactory.getAliases(advisedBeanName);
|
||||
for (String alias : aliases) {
|
||||
if (this.expressionPattern.matches(alias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Serialization support
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
// Rely on default serialization, just initialize state after deserialization.
|
||||
ois.defaultReadObject();
|
||||
|
||||
// Initialize transient fields.
|
||||
// pointcutExpression will be initialized lazily by checkReadyToMatch()
|
||||
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||
}
|
||||
|
||||
private static class DefensiveShadowMatch implements ShadowMatch {
|
||||
|
||||
private final ShadowMatch primary;
|
||||
private final ShadowMatch other;
|
||||
|
||||
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
|
||||
this.primary = primary;
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
public boolean alwaysMatches() {
|
||||
return primary.alwaysMatches();
|
||||
}
|
||||
|
||||
public boolean maybeMatches() {
|
||||
return primary.maybeMatches();
|
||||
}
|
||||
|
||||
public boolean neverMatches() {
|
||||
return primary.neverMatches();
|
||||
}
|
||||
|
||||
public JoinPointMatch matchesJoinPoint(Object thisObject,
|
||||
Object targetObject, Object[] args) {
|
||||
try {
|
||||
return primary.matchesJoinPoint(thisObject, targetObject, args);
|
||||
} catch (ReflectionWorldException e) {
|
||||
return other.matchesJoinPoint(thisObject, targetObject, args);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMatchingContext(MatchingContext aMatchContext) {
|
||||
primary.setMatchingContext(aMatchContext);
|
||||
other.setMatchingContext(aMatchContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.support.AbstractGenericPointcutAdvisor;
|
||||
|
||||
/**
|
||||
* Spring AOP Advisor that can be used for any AspectJ pointcut expression.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor {
|
||||
|
||||
private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.pointcut.setExpression(expression);
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.pointcut.setLocation(location);
|
||||
}
|
||||
|
||||
public void setParameterTypes(Class[] types) {
|
||||
this.pointcut.setParameterTypes(types);
|
||||
}
|
||||
|
||||
public void setParameterNames(String[] names) {
|
||||
this.pointcut.setParameterNames(names);
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return this.pointcut.getLocation();
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return this.pointcut.getExpression();
|
||||
}
|
||||
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
|
||||
/**
|
||||
* Spring AOP advice that wraps an AspectJ before method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice {
|
||||
|
||||
public AspectJMethodBeforeAdvice(
|
||||
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
|
||||
|
||||
super(aspectJBeforeAdviceMethod, pointcut, aif);
|
||||
}
|
||||
|
||||
public void before(Method method, Object[] args, Object target) throws Throwable {
|
||||
invokeAdviceMethod(getJoinPointMatch(), null, null);
|
||||
}
|
||||
|
||||
public boolean isBeforeAdvice() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAfterAdvice() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* AspectJPointcutAdvisor that adapts an {@link AbstractAspectJAdvice}
|
||||
* to the {@link org.springframework.aop.PointcutAdvisor} interface.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
|
||||
|
||||
private final AbstractAspectJAdvice advice;
|
||||
|
||||
private final Pointcut pointcut;
|
||||
|
||||
private Integer order;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AspectJPointcutAdvisor for the given advice
|
||||
* @param advice the AbstractAspectJAdvice to wrap
|
||||
*/
|
||||
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
|
||||
Assert.notNull(advice, "Advice must not be null");
|
||||
this.advice = advice;
|
||||
this.pointcut = advice.buildSafePointcut();
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
|
||||
public boolean isPerInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
return this.advice;
|
||||
}
|
||||
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
if (this.order != null) {
|
||||
return this.order;
|
||||
}
|
||||
else {
|
||||
return this.advice.getOrder();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof AspectJPointcutAdvisor)) {
|
||||
return false;
|
||||
}
|
||||
AspectJPointcutAdvisor otherAdvisor = (AspectJPointcutAdvisor) other;
|
||||
return (ObjectUtils.nullSafeEquals(this.advice, otherAdvisor.advice));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return AspectJPointcutAdvisor.class.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by types that can supply the information
|
||||
* needed to sort advice/advisors by AspectJ's precedence rules.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @since 2.0
|
||||
* @see org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator
|
||||
*/
|
||||
public interface AspectJPrecedenceInformation extends Ordered {
|
||||
|
||||
// Implementation note:
|
||||
// We need the level of indirection this interface provides as otherwise the
|
||||
// AspectJPrecedenceComparator must ask an Advisor for its Advice in all cases
|
||||
// in order to sort advisors. This causes problems with the
|
||||
// InstantiationModelAwarePointcutAdvisor which needs to delay creating
|
||||
// its advice for aspects with non-singleton instantiation models.
|
||||
|
||||
/**
|
||||
* The name of the aspect (bean) in which the advice was declared.
|
||||
*/
|
||||
String getAspectName();
|
||||
|
||||
/**
|
||||
* The declaration order of the advice member within the aspect.
|
||||
*/
|
||||
int getDeclarationOrder();
|
||||
|
||||
/**
|
||||
* Return whether this is a before advice.
|
||||
*/
|
||||
boolean isBeforeAdvice();
|
||||
|
||||
/**
|
||||
* Return whether this is an after advice.
|
||||
*/
|
||||
boolean isAfterAdvice();
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
|
||||
/**
|
||||
* Utility methods for working with AspectJ proxies.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AspectJProxyUtils {
|
||||
|
||||
/**
|
||||
* Add special advisors if necessary to work with a proxy chain that contains AspectJ advisors.
|
||||
* This will expose the current Spring AOP invocation (necessary for some AspectJ pointcut matching)
|
||||
* and make available the current AspectJ JoinPoint. The call will have no effect if there are no
|
||||
* AspectJ advisors in the advisor chain.
|
||||
* @param advisors Advisors available
|
||||
* @return <code>true</code> if any special {@link Advisor Advisors} were added, otherwise <code>false</code>.
|
||||
*/
|
||||
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
|
||||
// Don't add advisors to an empty list; may indicate that proxying is just not required
|
||||
if (!advisors.isEmpty()) {
|
||||
boolean foundAspectJAdvice = false;
|
||||
for (Advisor advisor : advisors) {
|
||||
// Be careful not to get the Advice without a guard, as
|
||||
// this might eagerly instantiate a non-singleton AspectJ aspect
|
||||
if (isAspectJAdvice(advisor)) {
|
||||
foundAspectJAdvice = true;
|
||||
}
|
||||
}
|
||||
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
|
||||
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given Advisor contains an AspectJ advice.
|
||||
* @param advisor the Advisor to check
|
||||
*/
|
||||
private static boolean isAspectJAdvice(Advisor advisor) {
|
||||
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
|
||||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
|
||||
(advisor instanceof PointcutAdvisor &&
|
||||
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
|
||||
}
|
||||
|
||||
}
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.bridge.AbortException;
|
||||
import org.aspectj.bridge.IMessage;
|
||||
import org.aspectj.bridge.IMessage.Kind;
|
||||
import org.aspectj.bridge.IMessageHandler;
|
||||
|
||||
/**
|
||||
* Implementation of AspectJ's {@link IMessageHandler} interface that
|
||||
* routes AspectJ weaving messages through the same logging system as the
|
||||
* regular Spring messages.
|
||||
*
|
||||
* <p>Pass the option...
|
||||
*
|
||||
* <p><code class="code">-XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler</code>
|
||||
*
|
||||
* <p>to the weaver; for example, specifying the following in a
|
||||
* "<code>META-INF/aop.xml</code> file:
|
||||
*
|
||||
* <p><code class="code"><weaver options="..."/></code>
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AspectJWeaverMessageHandler implements IMessageHandler {
|
||||
|
||||
private static final String AJ_ID = "[AspectJ] ";
|
||||
|
||||
private static final Log LOGGER = LogFactory.getLog("AspectJ Weaver");
|
||||
|
||||
|
||||
public boolean handleMessage(IMessage message) throws AbortException {
|
||||
Kind messageKind = message.getKind();
|
||||
|
||||
if (LOGGER.isDebugEnabled() || LOGGER.isTraceEnabled()) {
|
||||
if (messageKind == IMessage.DEBUG) {
|
||||
LOGGER.debug(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
if ((messageKind == IMessage.INFO) || (messageKind == IMessage.WEAVEINFO)) {
|
||||
LOGGER.info(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGER.isWarnEnabled()) {
|
||||
if (messageKind == IMessage.WARNING) {
|
||||
LOGGER.warn(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGER.isErrorEnabled()) {
|
||||
if (messageKind == IMessage.ERROR) {
|
||||
LOGGER.error(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGER.isFatalEnabled()) {
|
||||
if (messageKind == IMessage.ABORT) {
|
||||
LOGGER.fatal(makeMessageFor(message));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private String makeMessageFor(IMessage aMessage) {
|
||||
return AJ_ID + aMessage.getMessage();
|
||||
}
|
||||
|
||||
public boolean isIgnoring(Kind messageKind) {
|
||||
// We want to see everything, and allow configuration of log levels dynamically.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void dontIgnore(Kind messageKind) {
|
||||
// We weren't ignoring anything anyway...
|
||||
}
|
||||
|
||||
public void ignore(Kind kind) {
|
||||
// We weren't ignoring anything anyway...
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.aop.IntroductionAdvisor;
|
||||
import org.springframework.aop.support.ClassFilters;
|
||||
import org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor;
|
||||
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
|
||||
|
||||
/**
|
||||
* Introduction advisor delegating to the given object.
|
||||
* Implements AspectJ annotation-style behavior for the DeclareParents annotation.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DeclareParentsAdvisor implements IntroductionAdvisor {
|
||||
|
||||
private final Class introducedInterface;
|
||||
|
||||
private final ClassFilter typePatternClassFilter;
|
||||
|
||||
private final Advice advice;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new advisor for this DeclareParents field.
|
||||
* @param interfaceType static field defining the introduction
|
||||
* @param typePattern type pattern the introduction is restricted to
|
||||
* @param defaultImpl the default implementation class
|
||||
*/
|
||||
public DeclareParentsAdvisor(Class interfaceType, String typePattern, Class defaultImpl) {
|
||||
this(interfaceType, typePattern, defaultImpl,
|
||||
new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new advisor for this DeclareParents field.
|
||||
* @param interfaceType static field defining the introduction
|
||||
* @param typePattern type pattern the introduction is restricted to
|
||||
* @param delegateRef the delegate implementation object
|
||||
*/
|
||||
public DeclareParentsAdvisor(Class interfaceType, String typePattern, Object delegateRef) {
|
||||
this(interfaceType, typePattern, delegateRef.getClass(),
|
||||
new DelegatingIntroductionInterceptor(delegateRef));
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to share common code between impl-based delegate and reference-based delegate
|
||||
* (cannot use method such as init() to share common code, due the the use of final fields)
|
||||
* @param interfaceType static field defining the introduction
|
||||
* @param typePattern type pattern the introduction is restricted to
|
||||
* @param implementationClass implementation class
|
||||
* @param advice delegation advice
|
||||
*/
|
||||
private DeclareParentsAdvisor(Class interfaceType, String typePattern, Class implementationClass, Advice advice) {
|
||||
this.introducedInterface = interfaceType;
|
||||
ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
|
||||
|
||||
// Excludes methods implemented.
|
||||
ClassFilter exclusion = new ClassFilter() {
|
||||
public boolean matches(Class clazz) {
|
||||
return !(introducedInterface.isAssignableFrom(clazz));
|
||||
}
|
||||
};
|
||||
|
||||
this.typePatternClassFilter = ClassFilters.intersection(typePatternFilter, exclusion);
|
||||
this.advice = advice;
|
||||
}
|
||||
|
||||
|
||||
public ClassFilter getClassFilter() {
|
||||
return this.typePatternClassFilter;
|
||||
}
|
||||
|
||||
public void validateInterfaces() throws IllegalArgumentException {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public boolean isPerInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Advice getAdvice() {
|
||||
return this.advice;
|
||||
}
|
||||
|
||||
public Class[] getInterfaces() {
|
||||
return new Class[] {this.introducedInterface};
|
||||
}
|
||||
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.aop.PointcutAdvisor;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by Spring AOP Advisors wrapping AspectJ
|
||||
* aspects that may have a lazy initialization strategy. For example,
|
||||
* a perThis instantiation model would mean lazy initialization of the advice.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface InstantiationModelAwarePointcutAdvisor extends PointcutAdvisor {
|
||||
|
||||
/**
|
||||
* Return whether this advisor is lazily initializing its underlying advice.
|
||||
*/
|
||||
boolean isLazy();
|
||||
|
||||
/**
|
||||
* Return whether this advisor has already instantiated its advice.
|
||||
*/
|
||||
boolean isAdviceInstantiated();
|
||||
|
||||
}
|
||||
-290
@@ -1,290 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.aspectj.lang.reflect.SourceLocation;
|
||||
import org.aspectj.runtime.internal.AroundClosure;
|
||||
|
||||
import org.springframework.aop.ProxyMethodInvocation;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of AspectJ ProceedingJoinPoint interface
|
||||
* wrapping an AOP Alliance MethodInvocation.
|
||||
*
|
||||
* <p><b>Note</b>: the <code>getThis()</code> method returns the current Spring AOP proxy.
|
||||
* The <code>getTarget()</code> method returns the current Spring AOP target (which may be
|
||||
* <code>null</code> if there is no target), and is a plain POJO without any advice.
|
||||
* <b>If you want to call the object and have the advice take effect, use
|
||||
* <code>getThis()</code>.</b> A common example is casting the object to an
|
||||
* introduced interface in the implementation of an introduction.
|
||||
*
|
||||
* <p>Of course there is no such distinction between target and proxy in AspectJ.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Adrian Colyer
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, JoinPoint.StaticPart {
|
||||
|
||||
private final ProxyMethodInvocation methodInvocation;
|
||||
|
||||
private Object[] defensiveCopyOfArgs;
|
||||
|
||||
/** Lazily initialized signature object */
|
||||
private Signature signature;
|
||||
|
||||
/** Lazily initialized source location object */
|
||||
private SourceLocation sourceLocation;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new MethodInvocationProceedingJoinPoint, wrapping the given
|
||||
* Spring ProxyMethodInvocation object.
|
||||
* @param methodInvocation the Spring ProxyMethodInvocation object
|
||||
*/
|
||||
public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation) {
|
||||
Assert.notNull(methodInvocation, "MethodInvocation must not be null");
|
||||
this.methodInvocation = methodInvocation;
|
||||
}
|
||||
|
||||
public void set$AroundClosure(AroundClosure aroundClosure) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Object proceed() throws Throwable {
|
||||
return this.methodInvocation.invocableClone().proceed();
|
||||
}
|
||||
|
||||
public Object proceed(Object[] arguments) throws Throwable {
|
||||
Assert.notNull(arguments, "Argument array passed to proceed cannot be null");
|
||||
if (arguments.length != this.methodInvocation.getArguments().length) {
|
||||
throw new IllegalArgumentException("Expecting " +
|
||||
this.methodInvocation.getArguments().length + " arguments to proceed, " +
|
||||
"but was passed " + arguments.length + " arguments");
|
||||
}
|
||||
this.methodInvocation.setArguments(arguments);
|
||||
return this.methodInvocation.invocableClone(arguments).proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Spring AOP proxy. Cannot be <code>null</code>.
|
||||
*/
|
||||
public Object getThis() {
|
||||
return this.methodInvocation.getProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Spring AOP target. May be <code>null</code> if there is no target.
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return this.methodInvocation.getThis();
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
if (this.defensiveCopyOfArgs == null) {
|
||||
Object[] argsSource = this.methodInvocation.getArguments();
|
||||
this.defensiveCopyOfArgs = new Object[argsSource.length];
|
||||
System.arraycopy(argsSource, 0, this.defensiveCopyOfArgs, 0, argsSource.length);
|
||||
}
|
||||
return this.defensiveCopyOfArgs;
|
||||
}
|
||||
|
||||
public Signature getSignature() {
|
||||
if (this.signature == null) {
|
||||
this.signature = new MethodSignatureImpl();
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
public SourceLocation getSourceLocation() {
|
||||
if (this.sourceLocation == null) {
|
||||
this.sourceLocation = new SourceLocationImpl();
|
||||
}
|
||||
return this.sourceLocation;
|
||||
}
|
||||
|
||||
public String getKind() {
|
||||
return ProceedingJoinPoint.METHOD_EXECUTION;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
// TODO: It's just an adapter but returning 0 might still have side effects...
|
||||
return 0;
|
||||
}
|
||||
|
||||
public JoinPoint.StaticPart getStaticPart() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toShortString() {
|
||||
return "execution(" + getSignature().toShortString() + ")";
|
||||
}
|
||||
|
||||
public String toLongString() {
|
||||
return "execution(" + getSignature().toLongString() + ")";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "execution(" + getSignature().toString() + ")";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lazily initialized MethodSignature.
|
||||
*/
|
||||
private class MethodSignatureImpl implements MethodSignature {
|
||||
|
||||
private volatile String[] parameterNames;
|
||||
|
||||
public String getName() {
|
||||
return methodInvocation.getMethod().getName();
|
||||
}
|
||||
|
||||
public int getModifiers() {
|
||||
return methodInvocation.getMethod().getModifiers();
|
||||
}
|
||||
|
||||
public Class getDeclaringType() {
|
||||
return methodInvocation.getMethod().getDeclaringClass();
|
||||
}
|
||||
|
||||
public String getDeclaringTypeName() {
|
||||
return methodInvocation.getMethod().getDeclaringClass().getName();
|
||||
}
|
||||
|
||||
public Class getReturnType() {
|
||||
return methodInvocation.getMethod().getReturnType();
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return methodInvocation.getMethod();
|
||||
}
|
||||
|
||||
public Class[] getParameterTypes() {
|
||||
return methodInvocation.getMethod().getParameterTypes();
|
||||
}
|
||||
|
||||
public String[] getParameterNames() {
|
||||
if (this.parameterNames == null) {
|
||||
this.parameterNames = (new LocalVariableTableParameterNameDiscoverer()).getParameterNames(getMethod());
|
||||
}
|
||||
return this.parameterNames;
|
||||
}
|
||||
|
||||
public Class[] getExceptionTypes() {
|
||||
return methodInvocation.getMethod().getExceptionTypes();
|
||||
}
|
||||
|
||||
public String toShortString() {
|
||||
return toString(false, false, false, false);
|
||||
}
|
||||
|
||||
public String toLongString() {
|
||||
return toString(true, true, true, true);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toString(false, true, false, true);
|
||||
}
|
||||
|
||||
private String toString(boolean includeModifier, boolean includeReturnTypeAndArgs,
|
||||
boolean useLongReturnAndArgumentTypeName, boolean useLongTypeName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (includeModifier) {
|
||||
sb.append(Modifier.toString(getModifiers()));
|
||||
sb.append(" ");
|
||||
}
|
||||
if (includeReturnTypeAndArgs) {
|
||||
appendType(sb, getReturnType(), useLongReturnAndArgumentTypeName);
|
||||
sb.append(" ");
|
||||
}
|
||||
appendType(sb, getDeclaringType(), useLongTypeName);
|
||||
sb.append(".");
|
||||
sb.append(getMethod().getName());
|
||||
sb.append("(");
|
||||
Class[] parametersTypes = getParameterTypes();
|
||||
appendTypes(sb, parametersTypes, includeReturnTypeAndArgs, useLongReturnAndArgumentTypeName);
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendTypes(StringBuilder sb, Class<?>[] types,
|
||||
boolean includeArgs, boolean useLongReturnAndArgumentTypeName) {
|
||||
if (includeArgs) {
|
||||
for (int size = types.length, i = 0; i < size; i++) {
|
||||
appendType(sb, types[i], useLongReturnAndArgumentTypeName);
|
||||
if (i < size - 1) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (types.length != 0) {
|
||||
sb.append("..");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendType(StringBuilder sb, Class<?> type, boolean useLongTypeName) {
|
||||
if (type.isArray()) {
|
||||
appendType(sb, type.getComponentType(), useLongTypeName);
|
||||
sb.append("[]");
|
||||
}
|
||||
else {
|
||||
sb.append(useLongTypeName ? type.getName() : type.getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lazily initialized SourceLocation.
|
||||
*/
|
||||
private class SourceLocationImpl implements SourceLocation {
|
||||
|
||||
public Class getWithinType() {
|
||||
if (methodInvocation.getThis() == null) {
|
||||
throw new UnsupportedOperationException("No source location joinpoint available: target is null");
|
||||
}
|
||||
return methodInvocation.getThis().getClass();
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.aspectj.weaver.ResolvedType;
|
||||
import org.aspectj.weaver.ast.And;
|
||||
import org.aspectj.weaver.ast.Call;
|
||||
import org.aspectj.weaver.ast.FieldGetCall;
|
||||
import org.aspectj.weaver.ast.HasAnnotation;
|
||||
import org.aspectj.weaver.ast.ITestVisitor;
|
||||
import org.aspectj.weaver.ast.Instanceof;
|
||||
import org.aspectj.weaver.ast.Literal;
|
||||
import org.aspectj.weaver.ast.Not;
|
||||
import org.aspectj.weaver.ast.Or;
|
||||
import org.aspectj.weaver.ast.Test;
|
||||
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
|
||||
import org.aspectj.weaver.reflect.ReflectionVar;
|
||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||
import org.aspectj.weaver.tools.ShadowMatch;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* This class encapsulates some AspectJ internal knowledge that should be
|
||||
* pushed back into the AspectJ project in a future release.
|
||||
*
|
||||
* <p>It relies on implementation specific knowledge in AspectJ to break
|
||||
* encapsulation and do something AspectJ was not designed to do: query
|
||||
* the types of runtime tests that will be performed. The code here should
|
||||
* migrate to <code>ShadowMatch.getVariablesInvolvedInRuntimeTest()</code>
|
||||
* or some similar operation.
|
||||
*
|
||||
* <p>See <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=151593"/>.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
*/
|
||||
class RuntimeTestWalker {
|
||||
|
||||
private final Test runtimeTest;
|
||||
|
||||
|
||||
public RuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||
ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch;
|
||||
try {
|
||||
Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest");
|
||||
ReflectionUtils.makeAccessible(testField);
|
||||
this.runtimeTest = (Test) testField.get(shadowMatch);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring: Expected field " +
|
||||
"'runtimeTest' is not present on ShadowMatchImpl class.");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the test uses any of the this, target, at_this, at_target, and at_annotation vars,
|
||||
* then it tests subtype sensitive vars.
|
||||
*/
|
||||
public boolean testsSubtypeSensitiveVars() {
|
||||
return (this.runtimeTest != null &&
|
||||
new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
|
||||
}
|
||||
|
||||
public boolean testThisInstanceOfResidue(Class thisClass) {
|
||||
return (this.runtimeTest != null &&
|
||||
new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
|
||||
}
|
||||
|
||||
public boolean testTargetInstanceOfResidue(Class targetClass) {
|
||||
return (this.runtimeTest != null &&
|
||||
new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
|
||||
}
|
||||
|
||||
|
||||
private static class TestVisitorAdapter implements ITestVisitor {
|
||||
|
||||
protected static final int THIS_VAR = 0;
|
||||
protected static final int TARGET_VAR = 1;
|
||||
protected static final int AT_THIS_VAR = 3;
|
||||
protected static final int AT_TARGET_VAR = 4;
|
||||
protected static final int AT_ANNOTATION_VAR = 8;
|
||||
|
||||
public void visit(And e) {
|
||||
e.getLeft().accept(this);
|
||||
e.getRight().accept(this);
|
||||
}
|
||||
|
||||
public void visit(Or e) {
|
||||
e.getLeft().accept(this);
|
||||
e.getRight().accept(this);
|
||||
}
|
||||
|
||||
public void visit(Not e) {
|
||||
e.getBody().accept(this);
|
||||
}
|
||||
|
||||
public void visit(Instanceof i) {
|
||||
}
|
||||
|
||||
public void visit(Literal literal) {
|
||||
}
|
||||
|
||||
public void visit(Call call) {
|
||||
}
|
||||
|
||||
public void visit(FieldGetCall fieldGetCall) {
|
||||
}
|
||||
|
||||
public void visit(HasAnnotation hasAnnotation) {
|
||||
}
|
||||
|
||||
public void visit(MatchingContextBasedTest matchingContextTest) {
|
||||
}
|
||||
|
||||
protected int getVarType(ReflectionVar v) {
|
||||
try {
|
||||
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
|
||||
ReflectionUtils.makeAccessible(varTypeField);
|
||||
return (Integer) varTypeField.get(v);
|
||||
}
|
||||
catch (NoSuchFieldException noSuchFieldEx) {
|
||||
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " +
|
||||
"on the classpath is incompatible with this version of Spring:- expected field " +
|
||||
"'varType' is not present on ReflectionVar class");
|
||||
}
|
||||
catch (IllegalAccessException illegalAccessEx) {
|
||||
// Famous last words... but I don't see how this can happen given the
|
||||
// makeAccessible call above
|
||||
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private Class matchClass;
|
||||
private boolean matches;
|
||||
private int matchVarType;
|
||||
|
||||
public InstanceOfResidueTestVisitor(Class matchClass, boolean defaultMatches, int matchVarType) {
|
||||
this.matchClass = matchClass;
|
||||
this.matches = defaultMatches;
|
||||
this.matchVarType = matchVarType;
|
||||
}
|
||||
|
||||
public boolean instanceOfMatches(Test test) {
|
||||
test.accept(this);
|
||||
return matches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ResolvedType type = (ResolvedType) i.getType();
|
||||
int varType = getVarType((ReflectionVar) i.getVar());
|
||||
if (varType != this.matchVarType) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
|
||||
// Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins
|
||||
this.matches = typeClass.isAssignableFrom(this.matchClass);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
this.matches = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if residue of target(TYPE) kind. See SPR-3783 for more details.
|
||||
*/
|
||||
private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
|
||||
|
||||
public TargetInstanceOfResidueTestVisitor(Class targetClass) {
|
||||
super(targetClass, false, TARGET_VAR);
|
||||
}
|
||||
|
||||
public boolean targetInstanceOfMatches(Test test) {
|
||||
return instanceOfMatches(test);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if residue of this(TYPE) kind. See SPR-2979 for more details.
|
||||
*/
|
||||
private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
|
||||
|
||||
public ThisInstanceOfResidueTestVisitor(Class thisClass) {
|
||||
super(thisClass, true, THIS_VAR);
|
||||
}
|
||||
|
||||
// TODO: Optimization: Process only if this() specifies a type and not an identifier.
|
||||
public boolean thisInstanceOfMatches(Test test) {
|
||||
return instanceOfMatches(test);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
|
||||
|
||||
private final Object thisObj = new Object();
|
||||
private final Object targetObj = new Object();
|
||||
private final Object[] argsObjs = new Object[0];
|
||||
private boolean testsSubtypeSensitiveVars = false;
|
||||
|
||||
public boolean testsSubtypeSensitiveVars(Test aTest) {
|
||||
aTest.accept(this);
|
||||
return this.testsSubtypeSensitiveVars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Instanceof i) {
|
||||
ReflectionVar v = (ReflectionVar) i.getVar();
|
||||
Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs);
|
||||
if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(HasAnnotation hasAnn) {
|
||||
// If you thought things were bad before, now we sink to new levels of horror...
|
||||
ReflectionVar v = (ReflectionVar) hasAnn.getVar();
|
||||
int varType = getVarType(v);
|
||||
if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) {
|
||||
this.testsSubtypeSensitiveVars = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AspectInstanceFactory} that creates a new instance
|
||||
* of the specified aspect class for every {@link #getAspectInstance()} call.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class SimpleAspectInstanceFactory implements AspectInstanceFactory {
|
||||
|
||||
private final Class aspectClass;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SimpleAspectInstanceFactory for the given aspect class.
|
||||
* @param aspectClass the aspect class
|
||||
*/
|
||||
public SimpleAspectInstanceFactory(Class aspectClass) {
|
||||
Assert.notNull(aspectClass, "Aspect class must not be null");
|
||||
this.aspectClass = aspectClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified aspect class (never <code>null</code>).
|
||||
*/
|
||||
public final Class getAspectClass() {
|
||||
return this.aspectClass;
|
||||
}
|
||||
|
||||
|
||||
public final Object getAspectInstance() {
|
||||
try {
|
||||
return this.aspectClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + this.aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access element class [" + this.aspectClass.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getAspectClassLoader() {
|
||||
return this.aspectClass.getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the order for this factory's aspect instance,
|
||||
* either an instance-specific order expressed through implementing
|
||||
* the {@link org.springframework.core.Ordered} interface,
|
||||
* or a fallback order.
|
||||
* @see org.springframework.core.Ordered
|
||||
* @see #getOrderForAspectClass
|
||||
*/
|
||||
public int getOrder() {
|
||||
return getOrderForAspectClass(this.aspectClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a fallback order for the case that the aspect instance
|
||||
* does not express an instance-specific order through implementing
|
||||
* the {@link org.springframework.core.Ordered} interface.
|
||||
* <p>The default implementation simply returns <code>Ordered.LOWEST_PRECEDENCE</code>.
|
||||
* @param aspectClass the aspect class
|
||||
*/
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AspectInstanceFactory} that is backed by a
|
||||
* specified singleton object, returning the same instance for every
|
||||
* {@link #getAspectInstance()} call.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see SimpleAspectInstanceFactory
|
||||
*/
|
||||
public class SingletonAspectInstanceFactory implements AspectInstanceFactory {
|
||||
|
||||
private final Object aspectInstance;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SingletonAspectInstanceFactory for the given aspect instance.
|
||||
* @param aspectInstance the singleton aspect instance
|
||||
*/
|
||||
public SingletonAspectInstanceFactory(Object aspectInstance) {
|
||||
Assert.notNull(aspectInstance, "Aspect instance must not be null");
|
||||
this.aspectInstance = aspectInstance;
|
||||
}
|
||||
|
||||
|
||||
public final Object getAspectInstance() {
|
||||
return this.aspectInstance;
|
||||
}
|
||||
|
||||
public ClassLoader getAspectClassLoader() {
|
||||
return this.aspectInstance.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the order for this factory's aspect instance,
|
||||
* either an instance-specific order expressed through implementing
|
||||
* the {@link org.springframework.core.Ordered} interface,
|
||||
* or a fallback order.
|
||||
* @see org.springframework.core.Ordered
|
||||
* @see #getOrderForAspectClass
|
||||
*/
|
||||
public int getOrder() {
|
||||
if (this.aspectInstance instanceof Ordered) {
|
||||
return ((Ordered) this.aspectInstance).getOrder();
|
||||
}
|
||||
return getOrderForAspectClass(this.aspectInstance.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a fallback order for the case that the aspect instance
|
||||
* does not express an instance-specific order through implementing
|
||||
* the {@link org.springframework.core.Ordered} interface.
|
||||
* <p>The default implementation simply returns <code>Ordered.LOWEST_PRECEDENCE</code>.
|
||||
* @param aspectClass the aspect class
|
||||
*/
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj;
|
||||
|
||||
import org.aspectj.weaver.tools.PointcutParser;
|
||||
import org.aspectj.weaver.tools.TypePatternMatcher;
|
||||
|
||||
import org.springframework.aop.ClassFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring AOP {@link ClassFilter} implementation using AspectJ type matching.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class TypePatternClassFilter implements ClassFilter {
|
||||
|
||||
private String typePattern;
|
||||
|
||||
private TypePatternMatcher aspectJTypePatternMatcher;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link TypePatternClassFilter} class.
|
||||
* <p>This is the JavaBean constructor; be sure to set the
|
||||
* {@link #setTypePattern(String) typePattern} property, else a
|
||||
* no doubt fatal {@link IllegalStateException} will be thrown
|
||||
* when the {@link #matches(Class)} method is first invoked.
|
||||
*/
|
||||
public TypePatternClassFilter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fully configured {@link TypePatternClassFilter} using the
|
||||
* given type pattern.
|
||||
* @param typePattern the type pattern that AspectJ weaver should parse
|
||||
* @throws IllegalArgumentException if the supplied <code>typePattern</code> is <code>null</code>
|
||||
* or is recognized as invalid
|
||||
*/
|
||||
public TypePatternClassFilter(String typePattern) {
|
||||
setTypePattern(typePattern);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the AspectJ type pattern to match.
|
||||
* <p>Examples include:
|
||||
* <code class="code">
|
||||
* org.springframework.beans.*
|
||||
* </code>
|
||||
* This will match any class or interface in the given package.
|
||||
* <code class="code">
|
||||
* org.springframework.beans.ITestBean+
|
||||
* </code>
|
||||
* This will match the <code>ITestBean</code> interface and any class
|
||||
* that implements it.
|
||||
* <p>These conventions are established by AspectJ, not Spring AOP.
|
||||
* @param typePattern the type pattern that AspectJ weaver should parse
|
||||
* @throws IllegalArgumentException if the supplied <code>typePattern</code> is <code>null</code>
|
||||
* or is recognized as invalid
|
||||
*/
|
||||
public void setTypePattern(String typePattern) {
|
||||
Assert.notNull(typePattern);
|
||||
this.typePattern = typePattern;
|
||||
this.aspectJTypePatternMatcher =
|
||||
PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution().
|
||||
parseTypePattern(replaceBooleanOperators(typePattern));
|
||||
}
|
||||
|
||||
public String getTypePattern() {
|
||||
return typePattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the pointcut apply to the given interface or target class?
|
||||
* @param clazz candidate target class
|
||||
* @return whether the advice should apply to this candidate target class
|
||||
* @throws IllegalStateException if no {@link #setTypePattern(String)} has been set
|
||||
*/
|
||||
public boolean matches(Class clazz) {
|
||||
if (this.aspectJTypePatternMatcher == null) {
|
||||
throw new IllegalStateException("No 'typePattern' has been set via ctor/setter.");
|
||||
}
|
||||
return this.aspectJTypePatternMatcher.matches(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a type pattern has been specified in XML, the user cannot
|
||||
* write <code>and</code> as "&&" (though && will work).
|
||||
* We also allow <code>and</code> between two sub-expressions.
|
||||
* <p>This method converts back to <code>&&</code> for the AspectJ pointcut parser.
|
||||
*/
|
||||
private String replaceBooleanOperators(String pcExpr) {
|
||||
pcExpr = StringUtils.replace(pcExpr," and "," && ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
|
||||
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
|
||||
return pcExpr;
|
||||
}
|
||||
}
|
||||
-338
@@ -1,338 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.lang.annotation.After;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.AjType;
|
||||
import org.aspectj.lang.reflect.AjTypeSystem;
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.PrioritizedParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for factories that can create Spring AOP Advisors
|
||||
* given AspectJ classes from classes honoring the AspectJ 5 annotation syntax.
|
||||
*
|
||||
* <p>This class handles annotation parsing and validation functionality.
|
||||
* It does not actually generate Spring AOP Advisors, which is deferred to subclasses.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory {
|
||||
|
||||
protected static final ParameterNameDiscoverer ASPECTJ_ANNOTATION_PARAMETER_NAME_DISCOVERER =
|
||||
new AspectJAnnotationParameterNameDiscoverer();
|
||||
|
||||
private static final String AJC_MAGIC = "ajc$";
|
||||
|
||||
|
||||
/**
|
||||
* Find and return the first AspectJ annotation on the given method
|
||||
* (there <i>should</i> only be one anyway...)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
|
||||
Class<? extends Annotation>[] classesToLookFor = new Class[] {
|
||||
Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
|
||||
for (Class<? extends Annotation> c : classesToLookFor) {
|
||||
AspectJAnnotation foundAnnotation = findAnnotation(method, c);
|
||||
if (foundAnnotation != null) {
|
||||
return foundAnnotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
|
||||
A result = AnnotationUtils.findAnnotation(method, toLookFor);
|
||||
if (result != null) {
|
||||
return new AspectJAnnotation<A>(result);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected final ParameterNameDiscoverer parameterNameDiscoverer;
|
||||
|
||||
|
||||
protected AbstractAspectJAdvisorFactory() {
|
||||
PrioritizedParameterNameDiscoverer prioritizedParameterNameDiscoverer = new PrioritizedParameterNameDiscoverer();
|
||||
prioritizedParameterNameDiscoverer.addDiscoverer(ASPECTJ_ANNOTATION_PARAMETER_NAME_DISCOVERER);
|
||||
this.parameterNameDiscoverer = prioritizedParameterNameDiscoverer;
|
||||
}
|
||||
|
||||
/**
|
||||
* We consider something to be an AspectJ aspect suitable for use by the Spring AOP system
|
||||
* if it has the @Aspect annotation, and was not compiled by ajc. The reason for this latter test
|
||||
* is that aspects written in the code-style (AspectJ language) also have the annotation present
|
||||
* when compiled by ajc with the -1.5 flag, yet they cannot be consumed by Spring AOP.
|
||||
*/
|
||||
public boolean isAspect(Class<?> clazz) {
|
||||
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
|
||||
}
|
||||
|
||||
private boolean hasAspectAnnotation(Class<?> clazz) {
|
||||
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to detect this as "code-style" AspectJ aspects should not be
|
||||
* interpreted by Spring AOP.
|
||||
*/
|
||||
private boolean compiledByAjc(Class<?> clazz) {
|
||||
// The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and
|
||||
// annotation-style aspects. Therefore there is no 'clean' way to tell them apart. Here we rely on
|
||||
// an implementation detail of the AspectJ compiler.
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getName().startsWith(AJC_MAGIC)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void validate(Class<?> aspectClass) throws AopConfigException {
|
||||
// If the parent has the annotation and isn't abstract it's an error
|
||||
if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
|
||||
!Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
|
||||
throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
|
||||
aspectClass.getSuperclass().getName() + "]");
|
||||
}
|
||||
|
||||
AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
|
||||
if (!ajType.isAspect()) {
|
||||
throw new NotAnAtAspectException(aspectClass);
|
||||
}
|
||||
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {
|
||||
throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " +
|
||||
"This is not supported in Spring AOP.");
|
||||
}
|
||||
if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {
|
||||
throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " +
|
||||
"This is not supported in Spring AOP.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The pointcut and advice annotations both have an "argNames" member which contains a
|
||||
* comma-separated list of the argument names. We use this (if non-empty) to build the
|
||||
* formal parameters for the pointcut.
|
||||
*/
|
||||
protected AspectJExpressionPointcut createPointcutExpression(
|
||||
Method annotatedMethod, Class declarationScope, String[] pointcutParameterNames) {
|
||||
|
||||
Class<?> [] pointcutParameterTypes = new Class<?>[0];
|
||||
if (pointcutParameterNames != null) {
|
||||
pointcutParameterTypes = extractPointcutParameterTypes(pointcutParameterNames,annotatedMethod);
|
||||
}
|
||||
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(declarationScope,pointcutParameterNames,pointcutParameterTypes);
|
||||
ajexp.setLocation(annotatedMethod.toString());
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the pointcut parameters needed by aspectj based on the given argument names
|
||||
* and the argument types that are available from the adviceMethod. Needs to take into
|
||||
* account (ignore) any JoinPoint based arguments as these are not pointcut context but
|
||||
* rather part of the advice execution context (thisJoinPoint, thisJoinPointStaticPart)
|
||||
*/
|
||||
private Class<?>[] extractPointcutParameterTypes(String[] argNames, Method adviceMethod) {
|
||||
Class<?>[] ret = new Class<?>[argNames.length];
|
||||
Class<?>[] paramTypes = adviceMethod.getParameterTypes();
|
||||
if (argNames.length > paramTypes.length) {
|
||||
throw new IllegalStateException("Expecting at least " + argNames.length +
|
||||
" arguments in the advice declaration, but only found " + paramTypes.length);
|
||||
}
|
||||
// Make the simplifying assumption for now that all of the JoinPoint based arguments
|
||||
// come first in the advice declaration.
|
||||
int typeOffset = paramTypes.length - argNames.length;
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = paramTypes[i + typeOffset];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
protected enum AspectJAnnotationType {
|
||||
AtPointcut,
|
||||
AtBefore,
|
||||
AtAfter,
|
||||
AtAfterReturning,
|
||||
AtAfterThrowing,
|
||||
AtAround
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class modelling an AspectJ annotation, exposing its type enumeration and
|
||||
* pointcut String.
|
||||
*/
|
||||
protected static class AspectJAnnotation<A extends Annotation> {
|
||||
|
||||
private static final String[] EXPRESSION_PROPERTIES = new String[] {"value", "pointcut"};
|
||||
|
||||
private static Map<Class, AspectJAnnotationType> annotationTypes =
|
||||
new HashMap<Class, AspectJAnnotationType>();
|
||||
|
||||
static {
|
||||
annotationTypes.put(Pointcut.class,AspectJAnnotationType.AtPointcut);
|
||||
annotationTypes.put(After.class,AspectJAnnotationType.AtAfter);
|
||||
annotationTypes.put(AfterReturning.class,AspectJAnnotationType.AtAfterReturning);
|
||||
annotationTypes.put(AfterThrowing.class,AspectJAnnotationType.AtAfterThrowing);
|
||||
annotationTypes.put(Around.class,AspectJAnnotationType.AtAround);
|
||||
annotationTypes.put(Before.class,AspectJAnnotationType.AtBefore);
|
||||
}
|
||||
|
||||
private final A annotation;
|
||||
|
||||
private final AspectJAnnotationType annotationType;
|
||||
|
||||
private final String pointcutExpression;
|
||||
|
||||
private final String argumentNames;
|
||||
|
||||
public AspectJAnnotation(A annotation) {
|
||||
this.annotation = annotation;
|
||||
this.annotationType = determineAnnotationType(annotation);
|
||||
// We know these methods exist with the same name on each object,
|
||||
// but need to invoke them reflectively as there isn't a common interface.
|
||||
try {
|
||||
this.pointcutExpression = resolveExpression(annotation);
|
||||
this.argumentNames = (String) annotation.getClass().getMethod("argNames").invoke(annotation);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(annotation + " cannot be an AspectJ annotation", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private AspectJAnnotationType determineAnnotationType(A annotation) {
|
||||
for (Class type : annotationTypes.keySet()) {
|
||||
if (type.isInstance(annotation)) {
|
||||
return annotationTypes.get(type);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unknown annotation type: " + annotation.toString());
|
||||
}
|
||||
|
||||
private String resolveExpression(A annotation) throws Exception {
|
||||
String expression = null;
|
||||
for (String methodName : EXPRESSION_PROPERTIES) {
|
||||
Method method;
|
||||
try {
|
||||
method = annotation.getClass().getDeclaredMethod(methodName);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
method = null;
|
||||
}
|
||||
if (method != null) {
|
||||
String candidate = (String) method.invoke(annotation);
|
||||
if (StringUtils.hasText(candidate)) {
|
||||
expression = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
public AspectJAnnotationType getAnnotationType() {
|
||||
return this.annotationType;
|
||||
}
|
||||
|
||||
public A getAnnotation() {
|
||||
return this.annotation;
|
||||
}
|
||||
|
||||
public String getPointcutExpression() {
|
||||
return this.pointcutExpression;
|
||||
}
|
||||
|
||||
public String getArgumentNames() {
|
||||
return this.argumentNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.annotation.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ParameterNameDiscoverer implementation that analyzes the arg names
|
||||
* specified at the AspectJ annotation level.
|
||||
*/
|
||||
private static class AspectJAnnotationParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
public String[] getParameterNames(Method method) {
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
return new String[0];
|
||||
}
|
||||
AspectJAnnotation annotation = findAspectJAnnotationOnMethod(method);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
}
|
||||
StringTokenizer strTok = new StringTokenizer(annotation.getArgumentNames(), ",");
|
||||
if (strTok.countTokens() > 0) {
|
||||
String[] names = new String[strTok.countTokens()];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
names[i] = strTok.nextToken();
|
||||
}
|
||||
return names;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getParameterNames(Constructor ctor) {
|
||||
throw new UnsupportedOperationException("Spring AOP cannot handle constructor advice");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link AspectJAwareAdvisorAutoProxyCreator} subclass that processes all AspectJ
|
||||
* annotation aspects in the current application context, as well as Spring Advisors.
|
||||
*
|
||||
* <p>Any AspectJ annotated classes will automatically be recognized, and their
|
||||
* advice applied if Spring AOP's proxy-based model is capable of applying it.
|
||||
* This covers method execution joinpoints.
|
||||
*
|
||||
* <p>If the <aop:include> element is used, only @AspectJ beans with names matched by
|
||||
* an include pattern will be considered as defining aspects to use for Spring auto-proxying.
|
||||
*
|
||||
* <p>Processing of Spring Advisors follows the rules established in
|
||||
* {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory
|
||||
*/
|
||||
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
|
||||
|
||||
private List<Pattern> includePatterns;
|
||||
|
||||
private AspectJAdvisorFactory aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
|
||||
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* Set a list of regex patterns, matching eligible @AspectJ bean names.
|
||||
* <p>Default is to consider all @AspectJ beans as eligible.
|
||||
*/
|
||||
public void setIncludePatterns(List<String> patterns) {
|
||||
this.includePatterns = new ArrayList<Pattern>(patterns.size());
|
||||
for (String patternText : patterns) {
|
||||
this.includePatterns.add(Pattern.compile(patternText));
|
||||
}
|
||||
}
|
||||
|
||||
public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
|
||||
Assert.notNull(this.aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
super.initBeanFactory(beanFactory);
|
||||
this.aspectJAdvisorsBuilder =
|
||||
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<Advisor> findCandidateAdvisors() {
|
||||
// Add all the Spring advisors found according to superclass rules.
|
||||
List<Advisor> advisors = super.findCandidateAdvisors();
|
||||
// Build Advisors for all AspectJ aspects in the bean factory.
|
||||
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
|
||||
return advisors;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInfrastructureClass(Class beanClass) {
|
||||
// Previously we setProxyTargetClass(true) in the constructor, but that has too
|
||||
// broad an impact. Instead we now override isInfrastructureClass to avoid proxying
|
||||
// aspects. I'm not entirely happy with that as there is no good reason not
|
||||
// to advise aspects, except that it causes advice invocation to go through a
|
||||
// proxy, and if the aspect implements e.g the Ordered interface it will be
|
||||
// proxied by that interface and fail at runtime as the advice method is not
|
||||
// defined on the interface. We could potentially relax the restriction about
|
||||
// not advising aspects in the future.
|
||||
return (super.isInfrastructureClass(beanClass) || this.aspectJAdvisorFactory.isAspect(beanClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given aspect bean is eligible for auto-proxying.
|
||||
* <p>If no <aop:include> elements were used then "includePatterns" will be
|
||||
* <code>null</code> and all beans are included. If "includePatterns" is non-null,
|
||||
* then one of the patterns must match.
|
||||
*/
|
||||
protected boolean isEligibleAspectBean(String beanName) {
|
||||
if (this.includePatterns == null) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
for (Pattern pattern : this.includePatterns) {
|
||||
if (pattern.matcher(beanName).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclass of BeanFactoryAspectJAdvisorsBuilderAdapter that delegates to
|
||||
* surrounding AnnotationAwareAspectJAutoProxyCreator facilities.
|
||||
*/
|
||||
private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {
|
||||
|
||||
public BeanFactoryAspectJAdvisorsBuilderAdapter(
|
||||
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
|
||||
super(beanFactory, advisorFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEligibleBean(String beanName) {
|
||||
return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
|
||||
/**
|
||||
* Interface for factories that can create Spring AOP Advisors from classes
|
||||
* annotated with AspectJ annotation syntax.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see AspectMetadata
|
||||
* @see org.aspectj.lang.reflect.AjTypeSystem
|
||||
*/
|
||||
public interface AspectJAdvisorFactory {
|
||||
|
||||
/**
|
||||
* Determine whether or not the given class is an aspect, as reported
|
||||
* by AspectJ's {@link org.aspectj.lang.reflect.AjTypeSystem}.
|
||||
* <p>Will simply return <code>false</code> if the supposed aspect is
|
||||
* invalid (such as an extension of a concrete aspect class).
|
||||
* Will return true for some aspects that Spring AOP cannot process,
|
||||
* such as those with unsupported instantiation models.
|
||||
* Use the {@link #validate} method to handle these cases if necessary.
|
||||
* @param clazz the supposed annotation-style AspectJ class
|
||||
* @return whether or not this class is recognized by AspectJ as an aspect class
|
||||
*/
|
||||
boolean isAspect(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Is the given class a valid AspectJ aspect class?
|
||||
* @param aspectClass the supposed AspectJ annotation-style class to validate
|
||||
* @throws AopConfigException if the class is an invalid aspect
|
||||
* (which can never be legal)
|
||||
* @throws NotAnAtAspectException if the class is not an aspect at all
|
||||
* (which may or may not be legal, depending on the context)
|
||||
*/
|
||||
void validate(Class<?> aspectClass) throws AopConfigException;
|
||||
|
||||
/**
|
||||
* Build Spring AOP Advisors for all annotated At-AspectJ methods
|
||||
* on the specified aspect instance.
|
||||
* @param aif the aspect instance factory (not the aspect instance itself
|
||||
* in order to avoid eager instantiation)
|
||||
* @return a list of advisors for this class
|
||||
*/
|
||||
List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aif);
|
||||
|
||||
/**
|
||||
* Build a Spring AOP Advisor for the given AspectJ advice method.
|
||||
* @param candidateAdviceMethod the candidate advice method
|
||||
* @param aif the aspect instance factory
|
||||
* @param declarationOrderInAspect the declaration order within the aspect
|
||||
* @param aspectName the name of the aspect
|
||||
* @return <code>null</code> if the method is not an AspectJ advice method
|
||||
* or if it is a pointcut that will be used by other advice but will not
|
||||
* create a Spring advice in its own right
|
||||
*/
|
||||
Advisor getAdvisor(Method candidateAdviceMethod,
|
||||
MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName);
|
||||
|
||||
/**
|
||||
* Build a Spring AOP Advice for the given AspectJ advice method.
|
||||
* @param candidateAdviceMethod the candidate advice method
|
||||
* @param pointcut the corresponding AspectJ expression pointcut
|
||||
* @param aif the aspect instance factory
|
||||
* @param declarationOrderInAspect the declaration order within the aspect
|
||||
* @param aspectName the name of the aspect
|
||||
* @return <code>null</code> if the method is not an AspectJ advice method
|
||||
* or if it is a pointcut that will be used by other advice but will not
|
||||
* create a Spring advice in its own right
|
||||
* @see org.springframework.aop.aspectj.AspectJAroundAdvice
|
||||
* @see org.springframework.aop.aspectj.AspectJMethodBeforeAdvice
|
||||
* @see org.springframework.aop.aspectj.AspectJAfterAdvice
|
||||
* @see org.springframework.aop.aspectj.AspectJAfterReturningAdvice
|
||||
* @see org.springframework.aop.aspectj.AspectJAfterThrowingAdvice
|
||||
*/
|
||||
Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut pointcut,
|
||||
MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName);
|
||||
|
||||
}
|
||||
-210
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.AspectJProxyUtils;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.aop.framework.ProxyCreatorSupport;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* AspectJ-based proxy factory, allowing for programmatic building
|
||||
* of proxies which include AspectJ aspects (code style as well
|
||||
* Java 5 annotation style).
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.0
|
||||
* @see #addAspect(Object)
|
||||
* @see #addAspect(Class)
|
||||
* @see #getProxy()
|
||||
* @see #getProxy(ClassLoader)
|
||||
* @see org.springframework.aop.framework.ProxyFactory
|
||||
*/
|
||||
public class AspectJProxyFactory extends ProxyCreatorSupport {
|
||||
|
||||
/** Cache for singleton aspect instances */
|
||||
private static final Map<Class, Object> aspectCache = new HashMap<Class, Object>();
|
||||
|
||||
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AspectJProxyFactory.
|
||||
*/
|
||||
public AspectJProxyFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AspectJProxyFactory.
|
||||
* <p>Will proxy all interfaces that the given target implements.
|
||||
* @param target the target object to be proxied
|
||||
*/
|
||||
public AspectJProxyFactory(Object target) {
|
||||
Assert.notNull(target, "Target object must not be null");
|
||||
setInterfaces(ClassUtils.getAllInterfaces(target));
|
||||
setTarget(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>AspectJProxyFactory</code>.
|
||||
* No target, only interfaces. Must add interceptors.
|
||||
*/
|
||||
public AspectJProxyFactory(Class[] interfaces) {
|
||||
setInterfaces(interfaces);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the supplied aspect instance to the chain. The type of the aspect instance
|
||||
* supplied must be a singleton aspect. True singleton lifecycle is not honoured when
|
||||
* using this method - the caller is responsible for managing the lifecycle of any
|
||||
* aspects added in this way.
|
||||
* @param aspectInstance the AspectJ aspect instance
|
||||
*/
|
||||
public void addAspect(Object aspectInstance) {
|
||||
Class aspectClass = aspectInstance.getClass();
|
||||
String aspectName = aspectClass.getName();
|
||||
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
|
||||
if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
|
||||
throw new IllegalArgumentException(
|
||||
"Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect");
|
||||
}
|
||||
addAdvisorsFromAspectInstanceFactory(
|
||||
new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an aspect of the supplied type to the end of the advice chain.
|
||||
* @param aspectClass the AspectJ aspect class
|
||||
*/
|
||||
public void addAspect(Class aspectClass) {
|
||||
String aspectName = aspectClass.getName();
|
||||
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
|
||||
MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);
|
||||
addAdvisorsFromAspectInstanceFactory(instanceFactory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add all {@link Advisor Advisors} from the supplied {@link MetadataAwareAspectInstanceFactory}
|
||||
* to the current chain. Exposes any special purpose {@link Advisor Advisors} if needed.
|
||||
* @see AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary(List)
|
||||
*/
|
||||
private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
|
||||
List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
|
||||
advisors = AopUtils.findAdvisorsThatCanApply(advisors, getTargetClass());
|
||||
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
|
||||
OrderComparator.sort(advisors);
|
||||
addAdvisors(advisors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AspectMetadata} instance for the supplied aspect type.
|
||||
*/
|
||||
private AspectMetadata createAspectMetadata(Class aspectClass, String aspectName) {
|
||||
AspectMetadata am = new AspectMetadata(aspectClass, aspectName);
|
||||
if (!am.getAjType().isAspect()) {
|
||||
throw new IllegalArgumentException("Class [" + aspectClass.getName() + "] is not a valid aspect type");
|
||||
}
|
||||
return am;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MetadataAwareAspectInstanceFactory} for the supplied aspect type. If the aspect type
|
||||
* has no per clause, then a {@link SingletonMetadataAwareAspectInstanceFactory} is returned, otherwise
|
||||
* a {@link PrototypeAspectInstanceFactory} is returned.
|
||||
*/
|
||||
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
|
||||
AspectMetadata am, Class aspectClass, String aspectName) {
|
||||
|
||||
MetadataAwareAspectInstanceFactory instanceFactory = null;
|
||||
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
// Create a shared aspect instance.
|
||||
Object instance = getSingletonAspectInstance(aspectClass);
|
||||
instanceFactory = new SingletonMetadataAwareAspectInstanceFactory(instance, aspectName);
|
||||
}
|
||||
else {
|
||||
// Create a factory for independent aspect instances.
|
||||
instanceFactory = new SimpleMetadataAwareAspectInstanceFactory(aspectClass, aspectName);
|
||||
}
|
||||
return instanceFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton aspect instance for the supplied aspect type. An instance
|
||||
* is created if one cannot be found in the instance cache.
|
||||
*/
|
||||
private Object getSingletonAspectInstance(Class aspectClass) {
|
||||
synchronized (aspectCache) {
|
||||
Object instance = aspectCache.get(aspectClass);
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
try {
|
||||
instance = aspectClass.newInstance();
|
||||
aspectCache.put(aspectClass, instance);
|
||||
return instance;
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
throw new AopConfigException("Unable to instantiate aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new AopConfigException("Cannot access aspect class [" + aspectClass.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new proxy according to the settings in this factory.
|
||||
* <p>Can be called repeatedly. Effect will vary if we've added
|
||||
* or removed interfaces. Can add and remove interceptors.
|
||||
* <p>Uses a default class loader: Usually, the thread context class loader
|
||||
* (if necessary for proxy creation).
|
||||
* @return the new proxy
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getProxy() {
|
||||
return (T) createAopProxy().getProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new proxy according to the settings in this factory.
|
||||
* <p>Can be called repeatedly. Effect will vary if we've added
|
||||
* or removed interfaces. Can add and remove interceptors.
|
||||
* <p>Uses the given class loader (if necessary for proxy creation).
|
||||
* @param classLoader the class loader to create the proxy with
|
||||
* @return the new proxy
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getProxy(ClassLoader classLoader) {
|
||||
return (T) createAopProxy().getProxy(classLoader);
|
||||
}
|
||||
|
||||
}
|
||||
-176
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.AjType;
|
||||
import org.aspectj.lang.reflect.AjTypeSystem;
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.aspectj.TypePatternClassFilter;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.aop.support.ComposablePointcut;
|
||||
|
||||
/**
|
||||
* Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut
|
||||
* for the per clause.
|
||||
*
|
||||
* <p>Uses AspectJ 5 AJType reflection API, so is only supported on Java 5.
|
||||
* Enables us to work with different AspectJ instantiation models such as
|
||||
* "singleton", "pertarget" and "perthis".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.aop.aspectj.AspectJExpressionPointcut
|
||||
*/
|
||||
public class AspectMetadata {
|
||||
|
||||
/**
|
||||
* AspectJ reflection information (AspectJ 5 / Java 5 specific).
|
||||
*/
|
||||
private final AjType ajType;
|
||||
|
||||
/**
|
||||
* Spring AOP pointcut corresponding to the per clause of the
|
||||
* aspect. Will be the Pointcut.TRUE canonical instance in the
|
||||
* case of a singleton, otherwise an AspectJExpressionPointcut.
|
||||
*/
|
||||
private final Pointcut perClausePointcut;
|
||||
|
||||
/**
|
||||
* The name of this aspect as defined to Spring (the bean name) -
|
||||
* allows us to determine if two pieces of advice come from the
|
||||
* same aspect and hence their relative precedence.
|
||||
*/
|
||||
private String aspectName;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AspectMetadata instance for the given aspect class.
|
||||
* @param aspectClass the aspect class
|
||||
* @param aspectName the name of the aspect
|
||||
*/
|
||||
public AspectMetadata(Class<?> aspectClass, String aspectName) {
|
||||
this.aspectName = aspectName;
|
||||
|
||||
Class<?> currClass = aspectClass;
|
||||
AjType ajType = null;
|
||||
while (!currClass.equals(Object.class)) {
|
||||
AjType ajTypeToCheck = AjTypeSystem.getAjType(currClass);
|
||||
if (ajTypeToCheck.isAspect()) {
|
||||
ajType = ajTypeToCheck;
|
||||
break;
|
||||
}
|
||||
currClass = currClass.getSuperclass();
|
||||
}
|
||||
if (ajType == null) {
|
||||
throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
|
||||
}
|
||||
this.ajType = ajType;
|
||||
if (this.ajType.getDeclarePrecedence().length > 0) {
|
||||
throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP");
|
||||
}
|
||||
|
||||
switch (this.ajType.getPerClause().getKind()) {
|
||||
case SINGLETON :
|
||||
this.perClausePointcut = Pointcut.TRUE;
|
||||
return;
|
||||
case PERTARGET : case PERTHIS :
|
||||
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
|
||||
ajexp.setLocation("@Aspect annotation on " + aspectClass.getName());
|
||||
ajexp.setExpression(findPerClause(aspectClass));
|
||||
this.perClausePointcut = ajexp;
|
||||
return;
|
||||
case PERTYPEWITHIN :
|
||||
// Works with a type pattern
|
||||
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
|
||||
return;
|
||||
default :
|
||||
throw new AopConfigException(
|
||||
"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract contents from String of form <code>pertarget(contents)</code>.
|
||||
*/
|
||||
private String findPerClause(Class<?> aspectClass) {
|
||||
// TODO when AspectJ provides this, we can remove this hack. Hence we don't
|
||||
// bother to make it elegant. Or efficient. Or robust :-)
|
||||
String str = aspectClass.getAnnotation(Aspect.class).value();
|
||||
str = str.substring(str.indexOf("(") + 1);
|
||||
str = str.substring(0, str.length() - 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return AspectJ reflection information.
|
||||
*/
|
||||
public AjType getAjType() {
|
||||
return this.ajType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the aspect class.
|
||||
*/
|
||||
public Class getAspectClass() {
|
||||
return this.ajType.getJavaClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the aspect class.
|
||||
*/
|
||||
public String getAspectName() {
|
||||
return this.aspectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Spring pointcut expression for a singleton aspect.
|
||||
* (e.g. <code>Pointcut.TRUE</code> if it's a singleton).
|
||||
*/
|
||||
public Pointcut getPerClausePointcut() {
|
||||
return this.perClausePointcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the aspect is defined as "perthis" or "pertarget".
|
||||
*/
|
||||
public boolean isPerThisOrPerTarget() {
|
||||
PerClauseKind kind = getAjType().getPerClause().getKind();
|
||||
return (kind == PerClauseKind.PERTARGET || kind == PerClauseKind.PERTHIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the aspect is defined as "pertypewithin".
|
||||
*/
|
||||
public boolean isPerTypeWithin() {
|
||||
PerClauseKind kind = getAjType().getPerClause().getKind();
|
||||
return (kind == PerClauseKind.PERTYPEWITHIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the aspect needs to be lazily instantiated.
|
||||
*/
|
||||
public boolean isLazilyInstantiated() {
|
||||
return (isPerThisOrPerTarget() || isPerTypeWithin());
|
||||
}
|
||||
|
||||
}
|
||||
-122
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.aop.aspectj.AspectInstanceFactory} implementation
|
||||
* backed by a Spring {@link org.springframework.beans.factory.BeanFactory}.
|
||||
*
|
||||
* <p>Note that this may instantiate multiple times if using a prototype,
|
||||
* which probably won't give the semantics you expect.
|
||||
* Use a {@link LazySingletonAspectInstanceFactoryDecorator}
|
||||
* to wrap this to ensure only one new aspect comes back.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see LazySingletonAspectInstanceFactoryDecorator
|
||||
*/
|
||||
public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final AspectMetadata aspectMetadata;
|
||||
|
||||
|
||||
/**
|
||||
* Create a BeanFactoryAspectInstanceFactory. AspectJ will be called to
|
||||
* introspect to create AJType metadata using the type returned for the
|
||||
* given bean name from the BeanFactory.
|
||||
* @param beanFactory BeanFactory to obtain instance(s) from
|
||||
* @param name name of the bean
|
||||
*/
|
||||
public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) {
|
||||
this(beanFactory, name, beanFactory.getType(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BeanFactoryAspectInstanceFactory, providing a type that AspectJ should
|
||||
* introspect to create AJType metadata. Use if the BeanFactory may consider the type
|
||||
* to be a subclass (as when using CGLIB), and the information should relate to a superclass.
|
||||
* @param beanFactory BeanFactory to obtain instance(s) from
|
||||
* @param name the name of the bean
|
||||
* @param type the type that should be introspected by AspectJ
|
||||
*/
|
||||
public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name, Class type) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.name = name;
|
||||
this.aspectMetadata = new AspectMetadata(type, name);
|
||||
}
|
||||
|
||||
|
||||
public Object getAspectInstance() {
|
||||
return this.beanFactory.getBean(this.name);
|
||||
}
|
||||
|
||||
public ClassLoader getAspectClassLoader() {
|
||||
if (this.beanFactory instanceof ConfigurableBeanFactory) {
|
||||
return ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader();
|
||||
}
|
||||
else {
|
||||
return ClassUtils.getDefaultClassLoader();
|
||||
}
|
||||
}
|
||||
|
||||
public AspectMetadata getAspectMetadata() {
|
||||
return this.aspectMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the order for this factory's target aspect, either
|
||||
* an instance-specific order expressed through implementing the
|
||||
* {@link org.springframework.core.Ordered} interface (only
|
||||
* checked for singleton beans), or an order expressed through the
|
||||
* {@link org.springframework.core.annotation.Order} annotation
|
||||
* at the class level.
|
||||
* @see org.springframework.core.Ordered
|
||||
* @see org.springframework.core.annotation.Order
|
||||
*/
|
||||
public int getOrder() {
|
||||
Class<?> type = this.beanFactory.getType(this.name);
|
||||
if (type != null) {
|
||||
if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
|
||||
return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
|
||||
}
|
||||
Order order = type.getAnnotation(Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": bean name '" + this.name + "'";
|
||||
}
|
||||
|
||||
}
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper for retrieving @AspectJ beans from a BeanFactory and building
|
||||
* Spring Advisors based on them, for use with auto-proxying.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.2
|
||||
* @see AnnotationAwareAspectJAutoProxyCreator
|
||||
*/
|
||||
public class BeanFactoryAspectJAdvisorsBuilder {
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private final AspectJAdvisorFactory advisorFactory;
|
||||
|
||||
private List<String> aspectBeanNames;
|
||||
|
||||
private final Map<String, List<Advisor>> advisorsCache = new HashMap<String, List<Advisor>>();
|
||||
|
||||
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache =
|
||||
new HashMap<String, MetadataAwareAspectInstanceFactory>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new BeanFactoryAspectJAdvisorsBuilder for the given BeanFactory.
|
||||
* @param beanFactory the ListableBeanFactory to scan
|
||||
*/
|
||||
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
|
||||
this(beanFactory, new ReflectiveAspectJAdvisorFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BeanFactoryAspectJAdvisorsBuilder for the given BeanFactory.
|
||||
* @param beanFactory the ListableBeanFactory to scan
|
||||
* @param advisorFactory the AspectJAdvisorFactory to build each Advisor with
|
||||
*/
|
||||
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
|
||||
Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
|
||||
Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null");
|
||||
this.beanFactory = beanFactory;
|
||||
this.advisorFactory = advisorFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look for AspectJ-annotated aspect beans in the current bean factory,
|
||||
* and return to a list of Spring AOP Advisors representing them.
|
||||
* <p>Creates a Spring Advisor for each AspectJ advice method.
|
||||
* @return the list of {@link org.springframework.aop.Advisor} beans
|
||||
* @see #isEligibleBean
|
||||
*/
|
||||
public List<Advisor> buildAspectJAdvisors() {
|
||||
List<String> aspectNames = null;
|
||||
|
||||
synchronized (this) {
|
||||
aspectNames = this.aspectBeanNames;
|
||||
if (aspectNames == null) {
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
aspectNames = new LinkedList<String>();
|
||||
String[] beanNames =
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
|
||||
for (String beanName : beanNames) {
|
||||
if (!isEligibleBean(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// We must be careful not to instantiate beans eagerly as in this
|
||||
// case they would be cached by the Spring container but would not
|
||||
// have been weaved
|
||||
Class beanType = this.beanFactory.getType(beanName);
|
||||
if (beanType == null) {
|
||||
continue;
|
||||
}
|
||||
if (this.advisorFactory.isAspect(beanType)) {
|
||||
aspectNames.add(beanName);
|
||||
AspectMetadata amd = new AspectMetadata(beanType, beanName);
|
||||
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
|
||||
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
this.advisorsCache.put(beanName, classAdvisors);
|
||||
}
|
||||
else {
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
}
|
||||
advisors.addAll(classAdvisors);
|
||||
}
|
||||
else {
|
||||
// Per target or per this.
|
||||
if (this.beanFactory.isSingleton(beanName)) {
|
||||
throw new IllegalArgumentException("Bean with name '" + beanName +
|
||||
"' is a singleton, but aspect instantiation model is not singleton");
|
||||
}
|
||||
MetadataAwareAspectInstanceFactory factory =
|
||||
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
|
||||
this.aspectFactoryCache.put(beanName, factory);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.aspectBeanNames = aspectNames;
|
||||
return advisors;
|
||||
}
|
||||
}
|
||||
|
||||
if (aspectNames.isEmpty()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
for (String aspectName : aspectNames) {
|
||||
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
|
||||
if (cachedAdvisors != null) {
|
||||
advisors.addAll(cachedAdvisors);
|
||||
}
|
||||
else {
|
||||
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
|
||||
advisors.addAll(this.advisorFactory.getAdvisors(factory));
|
||||
}
|
||||
}
|
||||
return advisors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the aspect bean with the given name is eligible.
|
||||
* @param beanName the name of the aspect bean
|
||||
* @return whether the bean is eligible
|
||||
*/
|
||||
protected boolean isEligibleBean(String beanName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
-258
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aspectj.lang.reflect.PerClauseKind;
|
||||
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.aspectj.AspectJPrecedenceInformation;
|
||||
import org.springframework.aop.aspectj.InstantiationModelAwarePointcutAdvisor;
|
||||
import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotation;
|
||||
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
|
||||
import org.springframework.aop.support.Pointcuts;
|
||||
|
||||
/**
|
||||
* Internal implementation of AspectJPointcutAdvisor.
|
||||
* Note that there will be one instance of this advisor for each target method.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
class InstantiationModelAwarePointcutAdvisorImpl
|
||||
implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation {
|
||||
|
||||
private final AspectJExpressionPointcut declaredPointcut;
|
||||
|
||||
private Pointcut pointcut;
|
||||
|
||||
private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final boolean lazy;
|
||||
|
||||
private final AspectJAdvisorFactory atAspectJAdvisorFactory;
|
||||
|
||||
private Advice instantiatedAdvice;
|
||||
|
||||
private int declarationOrder;
|
||||
|
||||
private String aspectName;
|
||||
|
||||
private Boolean isBeforeAdvice;
|
||||
|
||||
private Boolean isAfterAdvice;
|
||||
|
||||
|
||||
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
|
||||
MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {
|
||||
|
||||
this.declaredPointcut = ajexp;
|
||||
this.method = method;
|
||||
this.atAspectJAdvisorFactory = af;
|
||||
this.aspectInstanceFactory = aif;
|
||||
this.declarationOrder = declarationOrderInAspect;
|
||||
this.aspectName = aspectName;
|
||||
|
||||
if (aif.getAspectMetadata().isLazilyInstantiated()) {
|
||||
// Static part of the pointcut is a lazy type.
|
||||
Pointcut preInstantiationPointcut =
|
||||
Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
|
||||
|
||||
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
|
||||
// If it's not a dynamic pointcut, it may be optimized out
|
||||
// by the Spring AOP infrastructure after the first evaluation.
|
||||
this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
|
||||
this.lazy = true;
|
||||
}
|
||||
else {
|
||||
// A singleton aspect.
|
||||
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
|
||||
this.pointcut = declaredPointcut;
|
||||
this.lazy = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The pointcut for Spring AOP to use. Actual behaviour of the pointcut will change
|
||||
* depending on the state of the advice.
|
||||
*/
|
||||
public Pointcut getPointcut() {
|
||||
return this.pointcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is only of interest for Spring AOP: AspectJ instantiation semantics
|
||||
* are much richer. In AspectJ terminology, all a return of <code>true</code>
|
||||
* means here is that the aspect is not a SINGLETON.
|
||||
*/
|
||||
public boolean isPerInstance() {
|
||||
return (getAspectMetadata().getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AspectJ AspectMetadata for this advisor.
|
||||
*/
|
||||
public AspectMetadata getAspectMetadata() {
|
||||
return this.aspectInstanceFactory.getAspectMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily instantiate advice if necessary.
|
||||
*/
|
||||
public synchronized Advice getAdvice() {
|
||||
if (this.instantiatedAdvice == null) {
|
||||
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
|
||||
}
|
||||
return this.instantiatedAdvice;
|
||||
}
|
||||
|
||||
public boolean isLazy() {
|
||||
return this.lazy;
|
||||
}
|
||||
|
||||
public synchronized boolean isAdviceInstantiated() {
|
||||
return (this.instantiatedAdvice != null);
|
||||
}
|
||||
|
||||
|
||||
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
|
||||
return this.atAspectJAdvisorFactory.getAdvice(
|
||||
this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
|
||||
}
|
||||
|
||||
public MetadataAwareAspectInstanceFactory getAspectInstanceFactory() {
|
||||
return this.aspectInstanceFactory;
|
||||
}
|
||||
|
||||
public AspectJExpressionPointcut getDeclaredPointcut() {
|
||||
return this.declaredPointcut;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return this.aspectInstanceFactory.getOrder();
|
||||
}
|
||||
|
||||
public String getAspectName() {
|
||||
return this.aspectName;
|
||||
}
|
||||
|
||||
public int getDeclarationOrder() {
|
||||
return this.declarationOrder;
|
||||
}
|
||||
|
||||
public boolean isBeforeAdvice() {
|
||||
if (this.isBeforeAdvice == null) {
|
||||
determineAdviceType();
|
||||
}
|
||||
return this.isBeforeAdvice;
|
||||
}
|
||||
|
||||
public boolean isAfterAdvice() {
|
||||
if (this.isAfterAdvice == null) {
|
||||
determineAdviceType();
|
||||
}
|
||||
return this.isAfterAdvice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates some logic from getAdvice, but importantly does not force
|
||||
* creation of the advice.
|
||||
*/
|
||||
private void determineAdviceType() {
|
||||
AspectJAnnotation<?> aspectJAnnotation =
|
||||
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.method);
|
||||
if (aspectJAnnotation == null) {
|
||||
this.isBeforeAdvice = false;
|
||||
this.isAfterAdvice = false;
|
||||
}
|
||||
else {
|
||||
switch (aspectJAnnotation.getAnnotationType()) {
|
||||
case AtAfter:
|
||||
case AtAfterReturning:
|
||||
case AtAfterThrowing:
|
||||
this.isAfterAdvice = true;
|
||||
this.isBeforeAdvice = false;
|
||||
break;
|
||||
case AtAround:
|
||||
case AtPointcut:
|
||||
this.isAfterAdvice = false;
|
||||
this.isBeforeAdvice = false;
|
||||
break;
|
||||
case AtBefore:
|
||||
this.isAfterAdvice = false;
|
||||
this.isBeforeAdvice = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InstantiationModelAwarePointcutAdvisor: expression [" + getDeclaredPointcut().getExpression() +
|
||||
"]; advice method [" + this.method + "]; perClauseKind=" +
|
||||
this.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pointcut implementation that changes its behaviour when the advice is instantiated.
|
||||
* Note that this is a <i>dynamic</i> pointcut. Otherwise it might
|
||||
* be optimized out if it does not at first match statically.
|
||||
*/
|
||||
private class PerTargetInstantiationModelPointcut extends DynamicMethodMatcherPointcut {
|
||||
|
||||
private final AspectJExpressionPointcut declaredPointcut;
|
||||
|
||||
private final Pointcut preInstantiationPointcut;
|
||||
|
||||
private LazySingletonAspectInstanceFactoryDecorator aspectInstanceFactory;
|
||||
|
||||
private PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut,
|
||||
Pointcut preInstantiationPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
|
||||
this.declaredPointcut = declaredPointcut;
|
||||
this.preInstantiationPointcut = preInstantiationPointcut;
|
||||
if (aspectInstanceFactory instanceof LazySingletonAspectInstanceFactoryDecorator) {
|
||||
this.aspectInstanceFactory = (LazySingletonAspectInstanceFactoryDecorator) aspectInstanceFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, Class targetClass) {
|
||||
// We're either instantiated and matching on declared pointcut, or uninstantiated matching on either pointcut
|
||||
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass)) ||
|
||||
this.preInstantiationPointcut.getMethodMatcher().matches(method, targetClass);
|
||||
}
|
||||
|
||||
public boolean matches(Method method, Class targetClass, Object[] args) {
|
||||
// This can match only on declared pointcut.
|
||||
return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
|
||||
}
|
||||
|
||||
private boolean isAspectMaterialized() {
|
||||
return (this.aspectInstanceFactory == null || this.aspectInstanceFactory.isMaterialized());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Decorator to cause a {@link MetadataAwareAspectInstanceFactory} to instantiate only once.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwareAspectInstanceFactory {
|
||||
|
||||
private final MetadataAwareAspectInstanceFactory maaif;
|
||||
|
||||
private volatile Object materialized;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new lazily initializing decorator for the given AspectInstanceFactory.
|
||||
* @param maaif the MetadataAwareAspectInstanceFactory to decorate
|
||||
*/
|
||||
public LazySingletonAspectInstanceFactoryDecorator(MetadataAwareAspectInstanceFactory maaif) {
|
||||
Assert.notNull(maaif, "AspectInstanceFactory must not be null");
|
||||
this.maaif = maaif;
|
||||
}
|
||||
|
||||
|
||||
public synchronized Object getAspectInstance() {
|
||||
if (this.materialized == null) {
|
||||
synchronized (this) {
|
||||
if (this.materialized == null) {
|
||||
this.materialized = this.maaif.getAspectInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.materialized;
|
||||
}
|
||||
|
||||
public boolean isMaterialized() {
|
||||
return (this.materialized != null);
|
||||
}
|
||||
|
||||
public ClassLoader getAspectClassLoader() {
|
||||
return this.maaif.getAspectClassLoader();
|
||||
}
|
||||
|
||||
public AspectMetadata getAspectMetadata() {
|
||||
return this.maaif.getAspectMetadata();
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return this.maaif.getOrder();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LazySingletonAspectInstanceFactoryDecorator: decorating " + this.maaif;
|
||||
}
|
||||
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.AspectInstanceFactory;
|
||||
|
||||
/**
|
||||
* Subinterface of {@link org.springframework.aop.aspectj.AspectInstanceFactory}
|
||||
* that returns {@link AspectMetadata} associated with AspectJ-annotated classes.
|
||||
*
|
||||
* <p>Ideally, AspectInstanceFactory would include this method itself, but because
|
||||
* AspectMetadata uses Java-5-only {@link org.aspectj.lang.reflect.AjType},
|
||||
* we need to split out this subinterface.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
* @see AspectMetadata
|
||||
* @see org.aspectj.lang.reflect.AjType
|
||||
*/
|
||||
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
|
||||
|
||||
/**
|
||||
* Return the AspectJ AspectMetadata for this factory's aspect.
|
||||
* @return the aspect metadata
|
||||
*/
|
||||
AspectMetadata getAspectMetadata();
|
||||
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
|
||||
/**
|
||||
* Extension of AopConfigException thrown when trying to perform
|
||||
* an advisor generation operation on a class that is not an
|
||||
* AspectJ annotation-style aspect.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class NotAnAtAspectException extends AopConfigException {
|
||||
|
||||
private Class<?> nonAspectClass;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new NotAnAtAspectException for the given class.
|
||||
* @param nonAspectClass the offending class
|
||||
*/
|
||||
public NotAnAtAspectException(Class<?> nonAspectClass) {
|
||||
super(nonAspectClass.getName() + " is not an @AspectJ aspect");
|
||||
this.nonAspectClass = nonAspectClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offending class.
|
||||
*/
|
||||
public Class<?> getNonAspectClass() {
|
||||
return this.nonAspectClass;
|
||||
}
|
||||
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
|
||||
/**
|
||||
* AspectInstanceFactory backed by a BeanFactory-provided prototype,
|
||||
* enforcing prototype semantics.
|
||||
*
|
||||
* <p>Note that this may instantiate multiple times, which probably won't give the
|
||||
* semantics you expect. Use a {@link LazySingletonAspectInstanceFactoryDecorator}
|
||||
* to wrap this to ensure only one new aspect comes back.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see LazySingletonAspectInstanceFactoryDecorator
|
||||
*/
|
||||
public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory {
|
||||
|
||||
/**
|
||||
* Create a PrototypeAspectInstanceFactory. AspectJ will be called to
|
||||
* introspect to create AJType metadata using the type returned for the
|
||||
* given bean name from the BeanFactory.
|
||||
* @param beanFactory the BeanFactory to obtain instance(s) from
|
||||
* @param name the name of the bean
|
||||
*/
|
||||
public PrototypeAspectInstanceFactory(BeanFactory beanFactory, String name) {
|
||||
super(beanFactory, name);
|
||||
if (!beanFactory.isPrototype(name)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot use PrototypeAspectInstanceFactory with bean named '" + name + "': not a prototype");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-283
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aspectj.lang.annotation.After;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.DeclareParents;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
import org.springframework.aop.aspectj.AbstractAspectJAdvice;
|
||||
import org.springframework.aop.aspectj.AspectJAfterAdvice;
|
||||
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
|
||||
import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
|
||||
import org.springframework.aop.aspectj.AspectJAroundAdvice;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
|
||||
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
|
||||
import org.springframework.aop.framework.AopConfigException;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.comparator.CompoundComparator;
|
||||
import org.springframework.util.comparator.InstanceComparator;
|
||||
|
||||
/**
|
||||
* Factory that can create Spring AOP Advisors given AspectJ classes from
|
||||
* classes honoring the AspectJ 5 annotation syntax, using reflection to
|
||||
* invoke the corresponding advice methods.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Adrian Colyer
|
||||
* @author Juergen Hoeller
|
||||
* @author Ramnivas Laddad
|
||||
* @author Phillip Webb
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory {
|
||||
|
||||
private static final Comparator<Method> METHOD_COMPARATOR;
|
||||
|
||||
static {
|
||||
CompoundComparator<Method> comparator = new CompoundComparator<Method>();
|
||||
comparator.addComparator(new ConvertingComparator<Method, Annotation>(
|
||||
new InstanceComparator<Annotation>(
|
||||
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
|
||||
new Converter<Method, Annotation>() {
|
||||
public Annotation convert(Method method) {
|
||||
AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
|
||||
return annotation == null ? null : annotation.getAnnotation();
|
||||
}
|
||||
}));
|
||||
comparator.addComparator(new ConvertingComparator<Method, String>(
|
||||
new Converter<Method, String>() {
|
||||
public String convert(Method method) {
|
||||
return method.getName();
|
||||
}
|
||||
}));
|
||||
METHOD_COMPARATOR = comparator;
|
||||
}
|
||||
|
||||
|
||||
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
|
||||
final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
|
||||
final String aspectName = maaif.getAspectMetadata().getAspectName();
|
||||
validate(aspectClass);
|
||||
|
||||
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
|
||||
// so that it will only instantiate once.
|
||||
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
|
||||
new LazySingletonAspectInstanceFactoryDecorator(maaif);
|
||||
|
||||
final List<Advisor> advisors = new LinkedList<Advisor>();
|
||||
for (Method method : getAdvisorMethods(aspectClass)) {
|
||||
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
|
||||
if (advisor != null) {
|
||||
advisors.add(advisor);
|
||||
}
|
||||
}
|
||||
|
||||
// If it's a per target aspect, emit the dummy instantiating aspect.
|
||||
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
|
||||
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
|
||||
advisors.add(0, instantiationAdvisor);
|
||||
}
|
||||
|
||||
// Find introduction fields.
|
||||
for (Field field : aspectClass.getDeclaredFields()) {
|
||||
Advisor advisor = getDeclareParentsAdvisor(field);
|
||||
if (advisor != null) {
|
||||
advisors.add(advisor);
|
||||
}
|
||||
}
|
||||
|
||||
return advisors;
|
||||
}
|
||||
|
||||
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
|
||||
final List<Method> methods = new LinkedList<Method>();
|
||||
ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method method) throws IllegalArgumentException {
|
||||
// Exclude pointcuts
|
||||
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
});
|
||||
Collections.sort(methods, METHOD_COMPARATOR);
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link org.springframework.aop.aspectj.DeclareParentsAdvisor}
|
||||
* for the given introduction field.
|
||||
* <p>Resulting Advisors will need to be evaluated for targets.
|
||||
* @param introductionField the field to introspect
|
||||
* @return <code>null</code> if not an Advisor
|
||||
*/
|
||||
private Advisor getDeclareParentsAdvisor(Field introductionField) {
|
||||
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
|
||||
if (declareParents == null) {
|
||||
// Not an introduction field
|
||||
return null;
|
||||
}
|
||||
|
||||
if (DeclareParents.class.equals(declareParents.defaultImpl())) {
|
||||
// This is what comes back if it wasn't set. This seems bizarre...
|
||||
// TODO this restriction possibly should be relaxed
|
||||
throw new IllegalStateException("defaultImpl must be set on DeclareParents");
|
||||
}
|
||||
|
||||
return new DeclareParentsAdvisor(
|
||||
introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
|
||||
}
|
||||
|
||||
|
||||
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
|
||||
int declarationOrderInAspect, String aspectName) {
|
||||
|
||||
validate(aif.getAspectMetadata().getAspectClass());
|
||||
|
||||
AspectJExpressionPointcut ajexp =
|
||||
getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
|
||||
if (ajexp == null) {
|
||||
return null;
|
||||
}
|
||||
return new InstantiationModelAwarePointcutAdvisorImpl(
|
||||
this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
|
||||
}
|
||||
|
||||
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
|
||||
AspectJAnnotation<?> aspectJAnnotation =
|
||||
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
|
||||
if (aspectJAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
AspectJExpressionPointcut ajexp =
|
||||
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
|
||||
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
|
||||
return ajexp;
|
||||
}
|
||||
|
||||
|
||||
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
|
||||
MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {
|
||||
|
||||
Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass();
|
||||
validate(candidateAspectClass);
|
||||
|
||||
AspectJAnnotation<?> aspectJAnnotation =
|
||||
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
|
||||
if (aspectJAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we get here, we know we have an AspectJ method.
|
||||
// Check that it's an AspectJ-annotated class
|
||||
if (!isAspect(candidateAspectClass)) {
|
||||
throw new AopConfigException("Advice must be declared inside an aspect type: " +
|
||||
"Offending method '" + candidateAdviceMethod + "' in class [" +
|
||||
candidateAspectClass.getName() + "]");
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
|
||||
}
|
||||
|
||||
AbstractAspectJAdvice springAdvice;
|
||||
|
||||
switch (aspectJAnnotation.getAnnotationType()) {
|
||||
case AtBefore:
|
||||
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
|
||||
break;
|
||||
case AtAfter:
|
||||
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
|
||||
break;
|
||||
case AtAfterReturning:
|
||||
springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
|
||||
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
|
||||
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
|
||||
springAdvice.setReturningName(afterReturningAnnotation.returning());
|
||||
}
|
||||
break;
|
||||
case AtAfterThrowing:
|
||||
springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
|
||||
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
|
||||
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
|
||||
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
|
||||
}
|
||||
break;
|
||||
case AtAround:
|
||||
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
|
||||
break;
|
||||
case AtPointcut:
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
|
||||
}
|
||||
return null;
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"Unsupported advice type on method " + candidateAdviceMethod);
|
||||
}
|
||||
|
||||
// Now to configure the advice...
|
||||
springAdvice.setAspectName(aspectName);
|
||||
springAdvice.setDeclarationOrder(declarationOrderInAspect);
|
||||
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
|
||||
if (argNames != null) {
|
||||
springAdvice.setArgumentNamesFromStringArray(argNames);
|
||||
}
|
||||
springAdvice.calculateArgumentBindings();
|
||||
return springAdvice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthetic advisor that instantiates the aspect.
|
||||
* Triggered by per-clause pointcut on non-singleton aspect.
|
||||
* The advice has no effect.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
|
||||
|
||||
public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
|
||||
super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() {
|
||||
public void before(Method method, Object[] args, Object target) {
|
||||
// Simply instantiate the aspect
|
||||
aif.getAspectInstance();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.SimpleAspectInstanceFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MetadataAwareAspectInstanceFactory} that
|
||||
* creates a new instance of the specified aspect class for every
|
||||
* {@link #getAspectInstance()} call.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstanceFactory
|
||||
implements MetadataAwareAspectInstanceFactory {
|
||||
|
||||
private final AspectMetadata metadata;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SimpleMetadataAwareAspectInstanceFactory for the given aspect class.
|
||||
* @param aspectClass the aspect class
|
||||
* @param aspectName the aspect name
|
||||
*/
|
||||
public SimpleMetadataAwareAspectInstanceFactory(Class aspectClass, String aspectName) {
|
||||
super(aspectClass);
|
||||
this.metadata = new AspectMetadata(aspectClass, aspectName);
|
||||
}
|
||||
|
||||
|
||||
public final AspectMetadata getAspectMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a fallback order for the case that the aspect instance
|
||||
* does not express an instance-specific order through implementing
|
||||
* the {@link org.springframework.core.Ordered} interface.
|
||||
* <p>The default implementation simply returns <code>Ordered.LOWEST_PRECEDENCE</code>.
|
||||
* @param aspectClass the aspect class
|
||||
*/
|
||||
@Override
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
Order order = aspectClass.getAnnotation(Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* Implementation of {@link MetadataAwareAspectInstanceFactory} that is backed
|
||||
* by a specified singleton object, returning the same instance for every
|
||||
* {@link #getAspectInstance()} call.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see SimpleMetadataAwareAspectInstanceFactory
|
||||
*/
|
||||
public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspectInstanceFactory
|
||||
implements MetadataAwareAspectInstanceFactory {
|
||||
|
||||
private final AspectMetadata metadata;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SingletonMetadataAwareAspectInstanceFactory for the given aspect.
|
||||
* @param aspectInstance the singleton aspect instance
|
||||
* @param aspectName the name of the aspect
|
||||
*/
|
||||
public SingletonMetadataAwareAspectInstanceFactory(Object aspectInstance, String aspectName) {
|
||||
super(aspectInstance);
|
||||
this.metadata = new AspectMetadata(aspectInstance.getClass(), aspectName);
|
||||
}
|
||||
|
||||
|
||||
public final AspectMetadata getAspectMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the aspect class carries an
|
||||
* {@link org.springframework.core.annotation.Order} annotation,
|
||||
* falling back to <code>Ordered.LOWEST_PRECEDENCE</code>.
|
||||
* @see org.springframework.core.annotation.Order
|
||||
*/
|
||||
@Override
|
||||
protected int getOrderForAspectClass(Class<?> aspectClass) {
|
||||
Order order = aspectClass.getAnnotation(Order.class);
|
||||
if (order != null) {
|
||||
return order.value();
|
||||
}
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
/**
|
||||
*
|
||||
* Classes enabling AspectJ 5 @Annotated classes to be used in Spring AOP.
|
||||
*
|
||||
* <p>Normally to be used through an AspectJAutoProxyCreator rather than directly.
|
||||
*
|
||||
*/
|
||||
package org.springframework.aop.aspectj.annotation;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user