MethodHandles.Lookup.defineClass for CGLIB class definition purposes
Spring's CGLIB fork is patched with local copies of affected files here, introducing the notion of a "contextClass" (e.g. the proxy superclass) which gets passed through to ReflectUtils.defineClass for delegating to MethodHandles.Lookup.defineClass eventually, against a privateLookupIn(contextClass) lookup context on JDK 9/10/11. Issue: SPR-15859
This commit is contained in:
parent
cdaa247861
commit
61c3db0869
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -205,9 +205,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
return createProxyClassAndInstance(enhancer, callbacks);
|
return createProxyClassAndInstance(enhancer, callbacks);
|
||||||
}
|
}
|
||||||
catch (CodeGenerationException | IllegalArgumentException ex) {
|
catch (CodeGenerationException | IllegalArgumentException ex) {
|
||||||
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
|
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
|
||||||
this.advised.getTargetClass() + "]: " +
|
": Common causes of this problem include using a final class or a non-visible class",
|
||||||
"Common causes of this problem include using a final class or a non-visible class",
|
|
||||||
ex);
|
ex);
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
|
|
@ -743,7 +742,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Object invokeJoinpoint() throws Throwable {
|
protected Object invokeJoinpoint() throws Throwable {
|
||||||
if (this.publicMethod) {
|
if (this.publicMethod && getMethod().getDeclaringClass() != Object.class) {
|
||||||
return this.methodProxy.invoke(this.target, this.arguments);
|
return this.methodProxy.invoke(this.target, this.arguments);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -82,22 +82,24 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
@Test
|
@Test
|
||||||
public void testRejectsPerCflowAspect() {
|
public void testRejectsPerCflowAspect() {
|
||||||
try {
|
try {
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(),"someBean"));
|
getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(), "someBean"));
|
||||||
fail("Cannot accept cflow");
|
fail("Cannot accept cflow");
|
||||||
}
|
}
|
||||||
catch (AopConfigException ex) {
|
catch (AopConfigException ex) {
|
||||||
assertTrue(ex.getMessage().indexOf("PERCFLOW") != -1);
|
assertTrue(ex.getMessage().contains("PERCFLOW"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRejectsPerCflowBelowAspect() {
|
public void testRejectsPerCflowBelowAspect() {
|
||||||
try {
|
try {
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(),"someBean"));
|
getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(), "someBean"));
|
||||||
fail("Cannot accept cflowbelow");
|
fail("Cannot accept cflowbelow");
|
||||||
}
|
}
|
||||||
catch (AopConfigException ex) {
|
catch (AopConfigException ex) {
|
||||||
assertTrue(ex.getMessage().indexOf("PERCFLOWBELOW") != -1);
|
assertTrue(ex.getMessage().contains("PERCFLOWBELOW"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,9 +229,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
int realAge = 65;
|
int realAge = 65;
|
||||||
target.setAge(realAge);
|
target.setAge(realAge);
|
||||||
PerTypeWithinAspectInstanceFactory aif = new PerTypeWithinAspectInstanceFactory();
|
PerTypeWithinAspectInstanceFactory aif = new PerTypeWithinAspectInstanceFactory();
|
||||||
TestBean itb = (TestBean) createProxy(target,
|
TestBean itb = (TestBean) createProxy(target, getFixture().getAdvisors(aif), TestBean.class);
|
||||||
getFixture().getAdvisors(aif),
|
|
||||||
TestBean.class);
|
|
||||||
assertEquals("No method calls", 0, aif.getInstantiationCount());
|
assertEquals("No method calls", 0, aif.getInstantiationCount());
|
||||||
assertEquals("Around advice must now apply", 0, itb.getAge());
|
assertEquals("Around advice must now apply", 0, itb.getAge());
|
||||||
|
|
||||||
|
|
@ -257,9 +257,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
assertEquals("Around advice must still apply", 1, itb.getAge());
|
assertEquals("Around advice must still apply", 1, itb.getAge());
|
||||||
assertEquals("Around advice must still apply", 2, itb.getAge());
|
assertEquals("Around advice must still apply", 2, itb.getAge());
|
||||||
|
|
||||||
TestBean itb2 = (TestBean) createProxy(target,
|
TestBean itb2 = (TestBean) createProxy(target, getFixture().getAdvisors(aif), TestBean.class);
|
||||||
getFixture().getAdvisors(aif),
|
|
||||||
TestBean.class);
|
|
||||||
assertEquals(1, aif.getInstantiationCount());
|
assertEquals(1, aif.getInstantiationCount());
|
||||||
assertEquals("Around advice be independent for second instance", 0, itb2.getAge());
|
assertEquals("Around advice be independent for second instance", 0, itb2.getAge());
|
||||||
assertEquals(2, aif.getInstantiationCount());
|
assertEquals(2, aif.getInstantiationCount());
|
||||||
|
|
@ -284,7 +282,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testNamedPointcutFromAspectLibraryWithBinding() {
|
public void testNamedPointcutFromAspectLibraryWithBinding() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target,
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new NamedPointcutAspectFromLibraryWithBinding(),"someBean")),
|
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(
|
||||||
|
new NamedPointcutAspectFromLibraryWithBinding(), "someBean")),
|
||||||
ITestBean.class);
|
ITestBean.class);
|
||||||
itb.setAge(10);
|
itb.setAge(10);
|
||||||
assertEquals("Around advice must apply", 20, itb.getAge());
|
assertEquals("Around advice must apply", 20, itb.getAge());
|
||||||
|
|
@ -296,7 +295,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
int realAge = 65;
|
int realAge = 65;
|
||||||
target.setAge(realAge);
|
target.setAge(realAge);
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target,
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance,"someBean")),
|
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, "someBean")),
|
||||||
ITestBean.class);
|
ITestBean.class);
|
||||||
assertEquals("Around advice must apply", -1, itb.getAge());
|
assertEquals("Around advice must apply", -1, itb.getAge());
|
||||||
assertEquals(realAge, target.getAge());
|
assertEquals(realAge, target.getAge());
|
||||||
|
|
@ -306,7 +305,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testBindingWithSingleArg() {
|
public void testBindingWithSingleArg() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target,
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(),"someBean")),
|
getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(), "someBean")),
|
||||||
ITestBean.class);
|
ITestBean.class);
|
||||||
itb.setAge(10);
|
itb.setAge(10);
|
||||||
assertEquals("Around advice must apply", 20, itb.getAge());
|
assertEquals("Around advice must apply", 20, itb.getAge());
|
||||||
|
|
@ -317,7 +317,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testBindingWithMultipleArgsDifferentlyOrdered() {
|
public void testBindingWithMultipleArgsDifferentlyOrdered() {
|
||||||
ManyValuedArgs target = new ManyValuedArgs();
|
ManyValuedArgs target = new ManyValuedArgs();
|
||||||
ManyValuedArgs mva = (ManyValuedArgs) createProxy(target,
|
ManyValuedArgs mva = (ManyValuedArgs) createProxy(target,
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(),"someBean")),
|
getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(), "someBean")),
|
||||||
ManyValuedArgs.class);
|
ManyValuedArgs.class);
|
||||||
|
|
||||||
String a = "a";
|
String a = "a";
|
||||||
|
|
@ -338,7 +339,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
assertFalse(notLockableTarget instanceof Lockable);
|
assertFalse(notLockableTarget instanceof Lockable);
|
||||||
NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget,
|
NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget,
|
||||||
getFixture().getAdvisors(
|
getFixture().getAdvisors(
|
||||||
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||||
NotLockable.class);
|
NotLockable.class);
|
||||||
assertTrue(notLockable1 instanceof Lockable);
|
assertTrue(notLockable1 instanceof Lockable);
|
||||||
Lockable lockable = (Lockable) notLockable1;
|
Lockable lockable = (Lockable) notLockable1;
|
||||||
|
|
@ -349,7 +350,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
NotLockable notLockable2Target = new NotLockable();
|
NotLockable notLockable2Target = new NotLockable();
|
||||||
NotLockable notLockable2 = (NotLockable) createProxy(notLockable2Target,
|
NotLockable notLockable2 = (NotLockable) createProxy(notLockable2Target,
|
||||||
getFixture().getAdvisors(
|
getFixture().getAdvisors(
|
||||||
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||||
NotLockable.class);
|
NotLockable.class);
|
||||||
assertTrue(notLockable2 instanceof Lockable);
|
assertTrue(notLockable2 instanceof Lockable);
|
||||||
Lockable lockable2 = (Lockable) notLockable2;
|
Lockable lockable2 = (Lockable) notLockable2;
|
||||||
|
|
@ -369,10 +370,10 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() {
|
public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() {
|
||||||
assertTrue(AopUtils.findAdvisorsThatCanApply(
|
assertTrue(AopUtils.findAdvisorsThatCanApply(
|
||||||
getFixture().getAdvisors(
|
getFixture().getAdvisors(
|
||||||
new SingletonMetadataAwareAspectInstanceFactory(
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||||
new MakeLockable(),"someBean")),
|
|
||||||
CannotBeUnlocked.class).isEmpty());
|
CannotBeUnlocked.class).isEmpty());
|
||||||
assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size());
|
assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -408,42 +409,34 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
|
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
|
||||||
List.class
|
List.class
|
||||||
),
|
),
|
||||||
CannotBeUnlocked.class);
|
List.class);
|
||||||
assertFalse("Type pattern must have excluded mixin", proxy instanceof Lockable);
|
assertFalse("Type pattern must have excluded mixin", proxy instanceof Lockable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prereq AspectJ 1.6.7
|
|
||||||
@Test
|
@Test
|
||||||
public void testIntroductionBasedOnAnnotationMatch_Spr5307() {
|
public void testIntroductionBasedOnAnnotationMatch_SPR5307() {
|
||||||
AnnotatedTarget target = new AnnotatedTargetImpl();
|
AnnotatedTarget target = new AnnotatedTargetImpl();
|
||||||
|
|
||||||
List<Advisor> advisors = getFixture().getAdvisors(
|
List<Advisor> advisors = getFixture().getAdvisors(
|
||||||
new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(),"someBean"));
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(), "someBean"));
|
||||||
Object proxy = createProxy(target,
|
Object proxy = createProxy(target, advisors, AnnotatedTarget.class);
|
||||||
advisors,
|
|
||||||
AnnotatedTarget.class);
|
|
||||||
System.out.println(advisors.get(1));
|
System.out.println(advisors.get(1));
|
||||||
assertTrue(proxy instanceof Lockable);
|
assertTrue(proxy instanceof Lockable);
|
||||||
Lockable lockable = (Lockable)proxy;
|
Lockable lockable = (Lockable)proxy;
|
||||||
lockable.locked();
|
lockable.locked();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
|
// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void testIntroductionWithArgumentBinding() {
|
public void testIntroductionWithArgumentBinding() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
|
|
||||||
List<Advisor> advisors = getFixture().getAdvisors(
|
List<Advisor> advisors = getFixture().getAdvisors(
|
||||||
new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(),"someBean"));
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(), "someBean"));
|
||||||
advisors.addAll(getFixture().getAdvisors(
|
advisors.addAll(getFixture().getAdvisors(
|
||||||
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")));
|
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")));
|
||||||
|
|
||||||
Modifiable modifiable = (Modifiable) createProxy(target,
|
Modifiable modifiable = (Modifiable) createProxy(target, advisors, ITestBean.class);
|
||||||
advisors,
|
|
||||||
ITestBean.class);
|
|
||||||
assertThat(modifiable, instanceOf(Modifiable.class));
|
assertThat(modifiable, instanceOf(Modifiable.class));
|
||||||
Lockable lockable = (Lockable) modifiable;
|
Lockable lockable = (Lockable) modifiable;
|
||||||
assertFalse(lockable.locked());
|
assertFalse(lockable.locked());
|
||||||
|
|
@ -477,11 +470,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testAspectMethodThrowsExceptionLegalOnSignature() {
|
public void testAspectMethodThrowsExceptionLegalOnSignature() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
UnsupportedOperationException expectedException = new UnsupportedOperationException();
|
UnsupportedOperationException expectedException = new UnsupportedOperationException();
|
||||||
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
|
List<Advisor> advisors = getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean"));
|
||||||
assertEquals("One advice method was found", 1, advisors.size());
|
assertEquals("One advice method was found", 1, advisors.size());
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
|
||||||
advisors,
|
|
||||||
ITestBean.class);
|
|
||||||
try {
|
try {
|
||||||
itb.getAge();
|
itb.getAge();
|
||||||
fail();
|
fail();
|
||||||
|
|
@ -497,11 +490,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testAspectMethodThrowsExceptionIllegalOnSignature() {
|
public void testAspectMethodThrowsExceptionIllegalOnSignature() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
RemoteException expectedException = new RemoteException();
|
RemoteException expectedException = new RemoteException();
|
||||||
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
|
List<Advisor> advisors = getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean"));
|
||||||
assertEquals("One advice method was found", 1, advisors.size());
|
assertEquals("One advice method was found", 1, advisors.size());
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
|
||||||
advisors,
|
|
||||||
ITestBean.class);
|
|
||||||
try {
|
try {
|
||||||
itb.getAge();
|
itb.getAge();
|
||||||
fail();
|
fail();
|
||||||
|
|
@ -522,10 +515,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
|
|
||||||
// Required everywhere we use AspectJ proxies
|
// Required everywhere we use AspectJ proxies
|
||||||
pf.addAdvice(ExposeInvocationInterceptor.INSTANCE);
|
pf.addAdvice(ExposeInvocationInterceptor.INSTANCE);
|
||||||
|
pf.addAdvisors(advisors);
|
||||||
for (Object a : advisors) {
|
|
||||||
pf.addAdvisor((Advisor) a);
|
|
||||||
}
|
|
||||||
|
|
||||||
pf.setExposeProxy(true);
|
pf.setExposeProxy(true);
|
||||||
return pf.getProxy();
|
return pf.getProxy();
|
||||||
|
|
@ -534,13 +524,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
@Test
|
@Test
|
||||||
public void testTwoAdvicesOnOneAspect() {
|
public void testTwoAdvicesOnOneAspect() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
|
|
||||||
TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
|
TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
|
||||||
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect,"someBean"));
|
List<Advisor> advisors = getFixture().getAdvisors(
|
||||||
|
new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect, "someBean"));
|
||||||
assertEquals("Two advice methods found", 2, advisors.size());
|
assertEquals("Two advice methods found", 2, advisors.size());
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
|
||||||
advisors,
|
|
||||||
ITestBean.class);
|
|
||||||
itb.setName("");
|
itb.setName("");
|
||||||
assertEquals(0, itb.getAge());
|
assertEquals(0, itb.getAge());
|
||||||
int newAge = 32;
|
int newAge = 32;
|
||||||
|
|
@ -551,16 +539,15 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
@Test
|
@Test
|
||||||
public void testAfterAdviceTypes() throws Exception {
|
public void testAfterAdviceTypes() throws Exception {
|
||||||
Echo target = new Echo();
|
Echo target = new Echo();
|
||||||
|
|
||||||
ExceptionHandling afterReturningAspect = new ExceptionHandling();
|
ExceptionHandling afterReturningAspect = new ExceptionHandling();
|
||||||
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect,"someBean"));
|
List<Advisor> advisors = getFixture().getAdvisors(
|
||||||
Echo echo = (Echo) createProxy(target,
|
new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect, "someBean"));
|
||||||
advisors,
|
Echo echo = (Echo) createProxy(target, advisors, Echo.class);
|
||||||
Echo.class);
|
|
||||||
assertEquals(0, afterReturningAspect.successCount);
|
assertEquals(0, afterReturningAspect.successCount);
|
||||||
assertEquals("", echo.echo(""));
|
assertEquals("", echo.echo(""));
|
||||||
assertEquals(1, afterReturningAspect.successCount);
|
assertEquals(1, afterReturningAspect.successCount);
|
||||||
assertEquals(0, afterReturningAspect.failureCount);
|
assertEquals(0, afterReturningAspect.failureCount);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
echo.echo(new FileNotFoundException());
|
echo.echo(new FileNotFoundException());
|
||||||
fail();
|
fail();
|
||||||
|
|
@ -580,9 +567,9 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testFailureWithoutExplicitDeclarePrecedence() {
|
public void testFailureWithoutExplicitDeclarePrecedence() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
|
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
|
||||||
new NoDeclarePrecedenceShouldFail(), "someBean");
|
new NoDeclarePrecedenceShouldFail(), "someBean");
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
ITestBean itb = (ITestBean) createProxy(target,
|
||||||
getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
|
getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
|
||||||
itb.getAge();
|
itb.getAge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,21 +577,10 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
|
||||||
public void testDeclarePrecedenceNotSupported() {
|
public void testDeclarePrecedenceNotSupported() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
|
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
|
||||||
new DeclarePrecedenceShouldSucceed(), "someBean");
|
new DeclarePrecedenceShouldSucceed(), "someBean");
|
||||||
createProxy(target, getFixture().getAdvisors(aspectInstanceFactory),
|
createProxy(target, getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
|
||||||
ITestBean.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Not supported in 2.0!
|
|
||||||
public void testExplicitDeclarePrecedencePreventsFailure() {
|
|
||||||
TestBean target = new TestBean();
|
|
||||||
ITestBean itb = (ITestBean) createProxy(target,
|
|
||||||
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new DeclarePrecedenceShouldSucceed(), "someBean")),
|
|
||||||
ITestBean.class);
|
|
||||||
assertEquals(666, itb.getAge());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
@Aspect("percflow(execution(* *(..)))")
|
@Aspect("percflow(execution(* *(..)))")
|
||||||
public static class PerCflowAspect {
|
public static class PerCflowAspect {
|
||||||
|
|
@ -1019,9 +995,7 @@ class MakeLockable {
|
||||||
public static Lockable mixin;
|
public static Lockable mixin;
|
||||||
|
|
||||||
@Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin")
|
@Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin")
|
||||||
public void checkNotLocked(
|
public void checkNotLocked( Lockable mixin) {
|
||||||
Lockable mixin) // Bind to arg
|
|
||||||
{
|
|
||||||
// Can also obtain the mixin (this) this way
|
// Can also obtain the mixin (this) this way
|
||||||
//Lockable mixin = (Lockable) jp.getThis();
|
//Lockable mixin = (Lockable) jp.getThis();
|
||||||
if (mixin.locked()) {
|
if (mixin.locked()) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,9 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.beans.factory.config;
|
package org.springframework.beans.factory.config;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
@ -56,7 +53,7 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setup() {
|
||||||
p1BeanDef = rootBeanDefinition(TestBean.class)
|
p1BeanDef = rootBeanDefinition(TestBean.class)
|
||||||
.addPropertyValue("name", "${" + P1 + "}")
|
.addPropertyValue("name", "${" + P1 + "}")
|
||||||
.getBeanDefinition();
|
.getBeanDefinition();
|
||||||
|
|
@ -66,16 +63,14 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
ppcProperties = new Properties();
|
ppcProperties = new Properties();
|
||||||
ppcProperties.setProperty(P1, P1_LOCAL_PROPS_VAL);
|
ppcProperties.setProperty(P1, P1_LOCAL_PROPS_VAL);
|
||||||
System.setProperty(P1, P1_SYSTEM_PROPS_VAL);
|
System.setProperty(P1, P1_SYSTEM_PROPS_VAL);
|
||||||
getModifiableSystemEnvironment().put(P1, P1_SYSTEM_ENV_VAL);
|
|
||||||
ppc = new PropertyPlaceholderConfigurer();
|
ppc = new PropertyPlaceholderConfigurer();
|
||||||
ppc.setProperties(ppcProperties);
|
ppc.setProperties(ppcProperties);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void cleanup() {
|
||||||
System.clearProperty(P1);
|
System.clearProperty(P1);
|
||||||
getModifiableSystemEnvironment().remove(P1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -95,7 +90,7 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveFromSystemProperties() {
|
public void resolveFromSystemProperties() {
|
||||||
getModifiableSystemEnvironment().put("otherKey", "systemValue");
|
System.setProperty("otherKey", "systemValue");
|
||||||
p1BeanDef = rootBeanDefinition(TestBean.class)
|
p1BeanDef = rootBeanDefinition(TestBean.class)
|
||||||
.addPropertyValue("name", "${" + P1 + "}")
|
.addPropertyValue("name", "${" + P1 + "}")
|
||||||
.addPropertyValue("sex", "${otherKey}")
|
.addPropertyValue("sex", "${otherKey}")
|
||||||
|
|
@ -105,12 +100,12 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
TestBean bean = bf.getBean(TestBean.class);
|
TestBean bean = bf.getBean(TestBean.class);
|
||||||
assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL));
|
assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL));
|
||||||
assertThat(bean.getSex(), equalTo("systemValue"));
|
assertThat(bean.getSex(), equalTo("systemValue"));
|
||||||
getModifiableSystemEnvironment().remove("otherKey");
|
System.clearProperty("otherKey");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveFromLocalProperties() {
|
public void resolveFromLocalProperties() {
|
||||||
tearDown(); // eliminate entries from system props/environment
|
System.clearProperty(P1);
|
||||||
registerWithGeneratedName(p1BeanDef, bf);
|
registerWithGeneratedName(p1BeanDef, bf);
|
||||||
ppc.postProcessBeanFactory(bf);
|
ppc.postProcessBeanFactory(bf);
|
||||||
TestBean bean = bf.getBean(TestBean.class);
|
TestBean bean = bf.getBean(TestBean.class);
|
||||||
|
|
@ -134,16 +129,6 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
assertThat(bean.getName(), equalTo(P1_SYSTEM_PROPS_VAL));
|
assertThat(bean.getName(), equalTo(P1_SYSTEM_PROPS_VAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void setSystemSystemPropertiesMode_toOverride_andResolveFromSystemEnvironment() {
|
|
||||||
registerWithGeneratedName(p1BeanDef, bf);
|
|
||||||
System.clearProperty(P1); // will now fall all the way back to system environment
|
|
||||||
ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE);
|
|
||||||
ppc.postProcessBeanFactory(bf);
|
|
||||||
TestBean bean = bf.getBean(TestBean.class);
|
|
||||||
assertThat(bean.getName(), equalTo(P1_SYSTEM_ENV_VAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setSystemSystemPropertiesMode_toOverride_andSetSearchSystemEnvironment_toFalse() {
|
public void setSystemSystemPropertiesMode_toOverride_andSetSearchSystemEnvironment_toFalse() {
|
||||||
registerWithGeneratedName(p1BeanDef, bf);
|
registerWithGeneratedName(p1BeanDef, bf);
|
||||||
|
|
@ -160,7 +145,7 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
* settings regarding resolving properties from the environment.
|
* settings regarding resolving properties from the environment.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void twoPlacholderConfigurers_withConflictingSettings() {
|
public void twoPlaceholderConfigurers_withConflictingSettings() {
|
||||||
String P2 = "p2";
|
String P2 = "p2";
|
||||||
String P2_LOCAL_PROPS_VAL = "p2LocalPropsVal";
|
String P2_LOCAL_PROPS_VAL = "p2LocalPropsVal";
|
||||||
String P2_SYSTEM_PROPS_VAL = "p2SystemPropsVal";
|
String P2_SYSTEM_PROPS_VAL = "p2SystemPropsVal";
|
||||||
|
|
@ -178,7 +163,6 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
ppc.postProcessBeanFactory(bf);
|
ppc.postProcessBeanFactory(bf);
|
||||||
|
|
||||||
System.setProperty(P2, P2_SYSTEM_PROPS_VAL);
|
System.setProperty(P2, P2_SYSTEM_PROPS_VAL);
|
||||||
getModifiableSystemEnvironment().put(P2, P2_SYSTEM_ENV_VAL);
|
|
||||||
Properties ppc2Properties = new Properties();
|
Properties ppc2Properties = new Properties();
|
||||||
ppc2Properties.put(P2, P2_LOCAL_PROPS_VAL);
|
ppc2Properties.put(P2, P2_LOCAL_PROPS_VAL);
|
||||||
|
|
||||||
|
|
@ -198,7 +182,6 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
assertThat(p2Bean.getCountry(), equalTo(P2_SYSTEM_PROPS_VAL));
|
assertThat(p2Bean.getCountry(), equalTo(P2_SYSTEM_PROPS_VAL));
|
||||||
|
|
||||||
System.clearProperty(P2);
|
System.clearProperty(P2);
|
||||||
getModifiableSystemEnvironment().remove(P2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -228,100 +211,41 @@ public class PropertyPlaceholderConfigurerTests {
|
||||||
public void nullValueIsPreserved() {
|
public void nullValueIsPreserved() {
|
||||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||||
ppc.setNullValue("customNull");
|
ppc.setNullValue("customNull");
|
||||||
getModifiableSystemEnvironment().put("my.name", "customNull");
|
System.setProperty("my.name", "customNull");
|
||||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
|
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
|
||||||
.addPropertyValue("name", "${my.name}")
|
.addPropertyValue("name", "${my.name}")
|
||||||
.getBeanDefinition());
|
.getBeanDefinition());
|
||||||
ppc.postProcessBeanFactory(bf);
|
ppc.postProcessBeanFactory(bf);
|
||||||
assertThat(bf.getBean(TestBean.class).getName(), nullValue());
|
assertThat(bf.getBean(TestBean.class).getName(), nullValue());
|
||||||
getModifiableSystemEnvironment().remove("my.name");
|
System.clearProperty("my.name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void trimValuesIsOffByDefault() {
|
public void trimValuesIsOffByDefault() {
|
||||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||||
getModifiableSystemEnvironment().put("my.name", " myValue ");
|
System.setProperty("my.name", " myValue ");
|
||||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
|
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
|
||||||
.addPropertyValue("name", "${my.name}")
|
.addPropertyValue("name", "${my.name}")
|
||||||
.getBeanDefinition());
|
.getBeanDefinition());
|
||||||
ppc.postProcessBeanFactory(bf);
|
ppc.postProcessBeanFactory(bf);
|
||||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo(" myValue "));
|
assertThat(bf.getBean(TestBean.class).getName(), equalTo(" myValue "));
|
||||||
getModifiableSystemEnvironment().remove("my.name");
|
System.clearProperty("my.name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void trimValuesIsApplied() {
|
public void trimValuesIsApplied() {
|
||||||
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
|
||||||
ppc.setTrimValues(true);
|
ppc.setTrimValues(true);
|
||||||
getModifiableSystemEnvironment().put("my.name", " myValue ");
|
System.setProperty("my.name", " myValue ");
|
||||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
|
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
|
||||||
.addPropertyValue("name", "${my.name}")
|
.addPropertyValue("name", "${my.name}")
|
||||||
.getBeanDefinition());
|
.getBeanDefinition());
|
||||||
ppc.postProcessBeanFactory(bf);
|
ppc.postProcessBeanFactory(bf);
|
||||||
assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue"));
|
assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue"));
|
||||||
getModifiableSystemEnvironment().remove("my.name");
|
System.clearProperty("my.name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static Map<String, String> getModifiableSystemEnvironment() {
|
|
||||||
// for os x / linux
|
|
||||||
Class<?>[] classes = Collections.class.getDeclaredClasses();
|
|
||||||
Map<String, String> env = System.getenv();
|
|
||||||
for (Class<?> cl : classes) {
|
|
||||||
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
|
|
||||||
try {
|
|
||||||
Field field = cl.getDeclaredField("m");
|
|
||||||
field.setAccessible(true);
|
|
||||||
Object obj = field.get(env);
|
|
||||||
if (obj != null && obj.getClass().getName().equals("java.lang.ProcessEnvironment$StringEnvironment")) {
|
|
||||||
return (Map<String, String>) obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for windows
|
|
||||||
Class<?> processEnvironmentClass;
|
|
||||||
try {
|
|
||||||
processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
|
|
||||||
theCaseInsensitiveEnvironmentField.setAccessible(true);
|
|
||||||
Object obj = theCaseInsensitiveEnvironmentField.get(null);
|
|
||||||
return (Map<String, String>) obj;
|
|
||||||
}
|
|
||||||
catch (NoSuchFieldException ex) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
|
|
||||||
theEnvironmentField.setAccessible(true);
|
|
||||||
Object obj = theEnvironmentField.get(null);
|
|
||||||
return (Map<String, String>) obj;
|
|
||||||
}
|
|
||||||
catch (NoSuchFieldException ex) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,9 +118,9 @@ class ConfigurationClassEnhancer {
|
||||||
/**
|
/**
|
||||||
* Creates a new CGLIB {@link Enhancer} instance.
|
* Creates a new CGLIB {@link Enhancer} instance.
|
||||||
*/
|
*/
|
||||||
private Enhancer newEnhancer(Class<?> superclass, @Nullable ClassLoader classLoader) {
|
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
|
||||||
Enhancer enhancer = new Enhancer();
|
Enhancer enhancer = new Enhancer();
|
||||||
enhancer.setSuperclass(superclass);
|
enhancer.setSuperclass(configSuperClass);
|
||||||
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
|
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
|
||||||
enhancer.setUseFactory(false);
|
enhancer.setUseFactory(false);
|
||||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -212,7 +212,7 @@ public abstract class AbstractAopProxyTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerializationSerializableTargetAndAdvice() throws Throwable {
|
public void testSerializableTargetAndAdvice() throws Throwable {
|
||||||
SerializablePerson personTarget = new SerializablePerson();
|
SerializablePerson personTarget = new SerializablePerson();
|
||||||
personTarget.setName("jim");
|
personTarget.setName("jim");
|
||||||
personTarget.setAge(26);
|
personTarget.setAge(26);
|
||||||
|
|
@ -435,7 +435,7 @@ public abstract class AbstractAopProxyTests {
|
||||||
TestBean raw = new OwnSpouse();
|
TestBean raw = new OwnSpouse();
|
||||||
|
|
||||||
ProxyCreatorSupport pc = new ProxyCreatorSupport();
|
ProxyCreatorSupport pc = new ProxyCreatorSupport();
|
||||||
pc.setInterfaces(new Class<?>[] {ITestBean.class});
|
pc.setInterfaces(ITestBean.class);
|
||||||
pc.setTarget(raw);
|
pc.setTarget(raw);
|
||||||
|
|
||||||
ITestBean tb = (ITestBean) createProxy(pc);
|
ITestBean tb = (ITestBean) createProxy(pc);
|
||||||
|
|
@ -457,7 +457,7 @@ public abstract class AbstractAopProxyTests {
|
||||||
pc.addAdvice(mi);
|
pc.addAdvice(mi);
|
||||||
|
|
||||||
// We don't care about the object
|
// We don't care about the object
|
||||||
mockTargetSource.setTarget(new Object());
|
mockTargetSource.setTarget(new TestBean());
|
||||||
pc.setTargetSource(mockTargetSource);
|
pc.setTargetSource(mockTargetSource);
|
||||||
AopProxy aop = createAopProxy(pc);
|
AopProxy aop = createAopProxy(pc);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -122,27 +122,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPackageMethodInvocationWithDifferentClassLoader() {
|
public void testProxyCanBeClassNotInterface() {
|
||||||
ClassLoader child = new ClassLoader(getClass().getClassLoader()) {
|
|
||||||
};
|
|
||||||
|
|
||||||
PackageMethodTestBean bean = new PackageMethodTestBean();
|
|
||||||
bean.value = "foo";
|
|
||||||
mockTargetSource.setTarget(bean);
|
|
||||||
|
|
||||||
AdvisedSupport as = new AdvisedSupport();
|
|
||||||
as.setTargetSource(mockTargetSource);
|
|
||||||
as.addAdvice(new NopInterceptor());
|
|
||||||
AopProxy aop = new CglibAopProxy(as);
|
|
||||||
|
|
||||||
PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy(child);
|
|
||||||
assertTrue(AopUtils.isCglibProxy(proxy));
|
|
||||||
assertNotEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
|
|
||||||
assertNull(proxy.getString()); // we're stuck in the proxy instance
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testProxyCanBeClassNotInterface() throws Exception {
|
|
||||||
TestBean raw = new TestBean();
|
TestBean raw = new TestBean();
|
||||||
raw.setAge(32);
|
raw.setAge(32);
|
||||||
mockTargetSource.setTarget(raw);
|
mockTargetSource.setTarget(raw);
|
||||||
|
|
@ -174,7 +154,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnadvisedProxyCreationWithCallDuringConstructor() throws Exception {
|
public void testUnadvisedProxyCreationWithCallDuringConstructor() {
|
||||||
CglibTestBean target = new CglibTestBean();
|
CglibTestBean target = new CglibTestBean();
|
||||||
target.setName("Rob Harrop");
|
target.setName("Rob Harrop");
|
||||||
|
|
||||||
|
|
@ -370,7 +350,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProxyProtectedMethod() throws Exception {
|
public void testProxyProtectedMethod() {
|
||||||
CountingBeforeAdvice advice = new CountingBeforeAdvice();
|
CountingBeforeAdvice advice = new CountingBeforeAdvice();
|
||||||
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
|
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
|
||||||
proxyFactory.addAdvice(advice);
|
proxyFactory.addAdvice(advice);
|
||||||
|
|
@ -382,14 +362,14 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProxyTargetClassInCaseOfNoInterfaces() throws Exception {
|
public void testProxyTargetClassInCaseOfNoInterfaces() {
|
||||||
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
|
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
|
||||||
MyBean proxy = (MyBean) proxyFactory.getProxy();
|
MyBean proxy = (MyBean) proxyFactory.getProxy();
|
||||||
assertEquals(4, proxy.add(1, 3));
|
assertEquals(4, proxy.add(1, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // SPR-13328
|
@Test // SPR-13328
|
||||||
public void testVarargsWithEnumArray() throws Exception {
|
public void testVarargsWithEnumArray() {
|
||||||
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
|
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
|
||||||
MyBean proxy = (MyBean) proxyFactory.getProxy();
|
MyBean proxy = (MyBean) proxyFactory.getProxy();
|
||||||
assertTrue(proxy.doWithVarargs(MyEnum.A, MyOtherEnum.C));
|
assertTrue(proxy.doWithVarargs(MyEnum.A, MyOtherEnum.C));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -35,13 +35,13 @@ import static org.junit.Assert.*;
|
||||||
public class BeanNameAutoProxyCreatorInitTests {
|
public class BeanNameAutoProxyCreatorInitTests {
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testIgnoreAdvisorThatIsCurrentlyCreation() {
|
public void testIgnoreAdvisorThatIsCurrentlyInCreation() {
|
||||||
ClassPathXmlApplicationContext ctx =
|
ClassPathXmlApplicationContext ctx =
|
||||||
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
|
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
|
||||||
TestBean bean = (TestBean) ctx.getBean("bean");
|
TestBean bean = (TestBean) ctx.getBean("bean");
|
||||||
bean.setName("foo");
|
bean.setName("foo");
|
||||||
assertEquals("foo", bean.getName());
|
assertEquals("foo", bean.getName());
|
||||||
bean.setName(null); // should throw
|
bean.setName(null); // should throw
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ task cglibRepackJar(type: Jar) { repackJar ->
|
||||||
}
|
}
|
||||||
// Repackage net.sf.cglib => org.springframework.cglib
|
// Repackage net.sf.cglib => org.springframework.cglib
|
||||||
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
|
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
|
||||||
// As mentioned above, transform cglib"s internal asm dependencies from
|
// As mentioned above, transform cglib's internal asm dependencies from
|
||||||
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
|
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
|
||||||
// the fact that Spring and cglib depend on the same version of asm!
|
// the fact that Spring and cglib depend on the same version of asm!
|
||||||
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
|
||||||
|
|
@ -98,6 +98,11 @@ jar {
|
||||||
dependsOn cglibRepackJar
|
dependsOn cglibRepackJar
|
||||||
from(zipTree(cglibRepackJar.archivePath)) {
|
from(zipTree(cglibRepackJar.archivePath)) {
|
||||||
include "org/springframework/cglib/**"
|
include "org/springframework/cglib/**"
|
||||||
|
exclude "org/springframework/cglib/core/AbstractClassGenerator*.class"
|
||||||
|
exclude "org/springframework/cglib/core/KeyFactory*.class"
|
||||||
|
exclude "org/springframework/cglib/core/ReflectUtils*.class"
|
||||||
|
exclude "org/springframework/cglib/proxy/Enhancer*.class"
|
||||||
|
exclude "org/springframework/cglib/proxy/MethodProxy*.class"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependsOn objenesisRepackJar
|
dependsOn objenesisRepackJar
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,379 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2003,2004 The Apache Software Foundation
|
||||||
|
*
|
||||||
|
* 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.cglib.core;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.springframework.asm.ClassReader;
|
||||||
|
import org.springframework.cglib.core.internal.Function;
|
||||||
|
import org.springframework.cglib.core.internal.LoadingCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for all code-generating CGLIB utilities.
|
||||||
|
* In addition to caching generated classes for performance, it provides hooks for
|
||||||
|
* customizing the <code>ClassLoader</code>, name of the generated class, and transformations
|
||||||
|
* applied before generation.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
abstract public class AbstractClassGenerator<T> implements ClassGenerator {
|
||||||
|
|
||||||
|
private static final ThreadLocal CURRENT = new ThreadLocal();
|
||||||
|
|
||||||
|
private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>();
|
||||||
|
|
||||||
|
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
|
||||||
|
|
||||||
|
private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;
|
||||||
|
|
||||||
|
private Source source;
|
||||||
|
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
private Class contextClass;
|
||||||
|
|
||||||
|
private String namePrefix;
|
||||||
|
|
||||||
|
private Object key;
|
||||||
|
|
||||||
|
private boolean useCache = true;
|
||||||
|
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
private boolean attemptLoad;
|
||||||
|
|
||||||
|
|
||||||
|
protected static class ClassLoaderData {
|
||||||
|
|
||||||
|
private final Set<String> reservedClassNames = new HashSet<String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link AbstractClassGenerator} here holds "cache key" (e.g. {@link org.springframework.cglib.proxy.Enhancer}
|
||||||
|
* configuration), and the value is the generated class plus some additional values
|
||||||
|
* (see {@link #unwrapCachedValue(Object)}.
|
||||||
|
* <p>The generated classes can be reused as long as their classloader is reachable.</p>
|
||||||
|
* <p>Note: the only way to access a class is to find it through generatedClasses cache, thus
|
||||||
|
* the key should not expire as long as the class itself is alive (its classloader is alive).</p>
|
||||||
|
*/
|
||||||
|
private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: ClassLoaderData object is stored as a value of {@code WeakHashMap<ClassLoader, ...>} thus
|
||||||
|
* this classLoader reference should be weak otherwise it would make classLoader strongly reachable
|
||||||
|
* and alive forever.
|
||||||
|
* Reference queue is not required since the cleanup is handled by {@link WeakHashMap}.
|
||||||
|
*/
|
||||||
|
private final WeakReference<ClassLoader> classLoader;
|
||||||
|
|
||||||
|
private final Predicate uniqueNamePredicate = new Predicate() {
|
||||||
|
public boolean evaluate(Object name) {
|
||||||
|
return reservedClassNames.contains(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
|
||||||
|
public Object apply(AbstractClassGenerator gen) {
|
||||||
|
return gen.key;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public ClassLoaderData(ClassLoader classLoader) {
|
||||||
|
if (classLoader == null) {
|
||||||
|
throw new IllegalArgumentException("classLoader == null is not yet supported");
|
||||||
|
}
|
||||||
|
this.classLoader = new WeakReference<ClassLoader>(classLoader);
|
||||||
|
Function<AbstractClassGenerator, Object> load =
|
||||||
|
new Function<AbstractClassGenerator, Object>() {
|
||||||
|
public Object apply(AbstractClassGenerator gen) {
|
||||||
|
Class klass = gen.generate(ClassLoaderData.this);
|
||||||
|
return gen.wrapCachedClass(klass);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassLoader getClassLoader() {
|
||||||
|
return classLoader.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reserveName(String name) {
|
||||||
|
reservedClassNames.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate getUniqueNamePredicate() {
|
||||||
|
return uniqueNamePredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(AbstractClassGenerator gen, boolean useCache) {
|
||||||
|
if (!useCache) {
|
||||||
|
return gen.generate(ClassLoaderData.this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Object cachedValue = generatedClasses.get(gen);
|
||||||
|
return gen.unwrapCachedValue(cachedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected T wrapCachedClass(Class klass) {
|
||||||
|
return (T) new WeakReference(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object unwrapCachedValue(T cached) {
|
||||||
|
return ((WeakReference) cached).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected static class Source {
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
public Source(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected AbstractClassGenerator(Source source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setNamePrefix(String namePrefix) {
|
||||||
|
this.namePrefix = namePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected String getClassName() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setClassName(String className) {
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateClassName(Predicate nameTestPredicate) {
|
||||||
|
return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the <code>ClassLoader</code> in which the class will be generated.
|
||||||
|
* Concrete subclasses of <code>AbstractClassGenerator</code> (such as <code>Enhancer</code>)
|
||||||
|
* will try to choose an appropriate default if this is unset.
|
||||||
|
* <p>
|
||||||
|
* Classes are cached per-<code>ClassLoader</code> using a <code>WeakHashMap</code>, to allow
|
||||||
|
* the generated classes to be removed when the associated loader is garbage collected.
|
||||||
|
* @param classLoader the loader to generate the new class with, or null to use the default
|
||||||
|
*/
|
||||||
|
public void setClassLoader(ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPRING PATCH BEGIN
|
||||||
|
public void setContextClass(Class contextClass) {
|
||||||
|
this.contextClass = contextClass;
|
||||||
|
}
|
||||||
|
// SPRING PATCH END
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the default naming policy.
|
||||||
|
* @param namingPolicy the custom policy, or null to use the default
|
||||||
|
* @see DefaultNamingPolicy
|
||||||
|
*/
|
||||||
|
public void setNamingPolicy(NamingPolicy namingPolicy) {
|
||||||
|
if (namingPolicy == null)
|
||||||
|
namingPolicy = DefaultNamingPolicy.INSTANCE;
|
||||||
|
this.namingPolicy = namingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #setNamingPolicy
|
||||||
|
*/
|
||||||
|
public NamingPolicy getNamingPolicy() {
|
||||||
|
return namingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether use and update the static cache of generated classes
|
||||||
|
* for a class with the same properties. Default is <code>true</code>.
|
||||||
|
*/
|
||||||
|
public void setUseCache(boolean useCache) {
|
||||||
|
this.useCache = useCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #setUseCache
|
||||||
|
*/
|
||||||
|
public boolean getUseCache() {
|
||||||
|
return useCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, CGLIB will attempt to load classes from the specified
|
||||||
|
* <code>ClassLoader</code> before generating them. Because generated
|
||||||
|
* class names are not guaranteed to be unique, the default is <code>false</code>.
|
||||||
|
*/
|
||||||
|
public void setAttemptLoad(boolean attemptLoad) {
|
||||||
|
this.attemptLoad = attemptLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getAttemptLoad() {
|
||||||
|
return attemptLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the strategy to use to create the bytecode from this generator.
|
||||||
|
* By default an instance of {@see DefaultGeneratorStrategy} is used.
|
||||||
|
*/
|
||||||
|
public void setStrategy(GeneratorStrategy strategy) {
|
||||||
|
if (strategy == null)
|
||||||
|
strategy = DefaultGeneratorStrategy.INSTANCE;
|
||||||
|
this.strategy = strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #setStrategy
|
||||||
|
*/
|
||||||
|
public GeneratorStrategy getStrategy() {
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally by CGLIB. Returns the <code>AbstractClassGenerator</code>
|
||||||
|
* that is being used to generate a class in the current thread.
|
||||||
|
*/
|
||||||
|
public static AbstractClassGenerator getCurrent() {
|
||||||
|
return (AbstractClassGenerator) CURRENT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassLoader getClassLoader() {
|
||||||
|
ClassLoader t = classLoader;
|
||||||
|
if (t == null) {
|
||||||
|
t = getDefaultClassLoader();
|
||||||
|
}
|
||||||
|
if (t == null) {
|
||||||
|
t = getClass().getClassLoader();
|
||||||
|
}
|
||||||
|
if (t == null) {
|
||||||
|
t = Thread.currentThread().getContextClassLoader();
|
||||||
|
}
|
||||||
|
if (t == null) {
|
||||||
|
throw new IllegalStateException("Cannot determine classloader");
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected ClassLoader getDefaultClassLoader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the protection domain to use when defining the class.
|
||||||
|
* <p>
|
||||||
|
* Default implementation returns <code>null</code> for using a default protection domain. Sub-classes may
|
||||||
|
* override to use a more specific protection domain.
|
||||||
|
* </p>
|
||||||
|
* @return the protection domain (<code>null</code> for using a default)
|
||||||
|
*/
|
||||||
|
protected ProtectionDomain getProtectionDomain() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object create(Object key) {
|
||||||
|
try {
|
||||||
|
ClassLoader loader = getClassLoader();
|
||||||
|
Map<ClassLoader, ClassLoaderData> cache = CACHE;
|
||||||
|
ClassLoaderData data = cache.get(loader);
|
||||||
|
if (data == null) {
|
||||||
|
synchronized (AbstractClassGenerator.class) {
|
||||||
|
cache = CACHE;
|
||||||
|
data = cache.get(loader);
|
||||||
|
if (data == null) {
|
||||||
|
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
|
||||||
|
data = new ClassLoaderData(loader);
|
||||||
|
newCache.put(loader, data);
|
||||||
|
CACHE = newCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.key = key;
|
||||||
|
Object obj = data.get(this, getUseCache());
|
||||||
|
if (obj instanceof Class) {
|
||||||
|
return firstInstance((Class) obj);
|
||||||
|
}
|
||||||
|
return nextInstance(obj);
|
||||||
|
}
|
||||||
|
catch (RuntimeException | Error ex) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class generate(ClassLoaderData data) {
|
||||||
|
Class gen;
|
||||||
|
Object save = CURRENT.get();
|
||||||
|
CURRENT.set(this);
|
||||||
|
try {
|
||||||
|
ClassLoader classLoader = data.getClassLoader();
|
||||||
|
if (classLoader == null) {
|
||||||
|
throw new IllegalStateException("ClassLoader is null while trying to define class " +
|
||||||
|
getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
|
||||||
|
"Please file an issue at cglib's issue tracker.");
|
||||||
|
}
|
||||||
|
synchronized (classLoader) {
|
||||||
|
String name = generateClassName(data.getUniqueNamePredicate());
|
||||||
|
data.reserveName(name);
|
||||||
|
this.setClassName(name);
|
||||||
|
}
|
||||||
|
if (attemptLoad) {
|
||||||
|
try {
|
||||||
|
gen = classLoader.loadClass(getClassName());
|
||||||
|
return gen;
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] b = strategy.generate(this);
|
||||||
|
String className = ClassNameReader.getClassName(new ClassReader(b));
|
||||||
|
ProtectionDomain protectionDomain = getProtectionDomain();
|
||||||
|
synchronized (classLoader) { // just in case
|
||||||
|
// SPRING PATCH BEGIN
|
||||||
|
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);
|
||||||
|
// SPRING PATCH END
|
||||||
|
}
|
||||||
|
return gen;
|
||||||
|
}
|
||||||
|
catch (RuntimeException | Error ex) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
CURRENT.set(save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected Object firstInstance(Class type) throws Exception;
|
||||||
|
|
||||||
|
abstract protected Object nextInstance(Object instance) throws Exception;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,363 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2003,2004 The Apache Software Foundation
|
||||||
|
*
|
||||||
|
* 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.cglib.core;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.asm.ClassVisitor;
|
||||||
|
import org.springframework.asm.Label;
|
||||||
|
import org.springframework.asm.Type;
|
||||||
|
import org.springframework.cglib.core.internal.CustomizerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
|
||||||
|
* Code for <code>equals</code> and <code>hashCode</code> methods follow the
|
||||||
|
* the rules laid out in <i>Effective Java</i> by Joshua Bloch.
|
||||||
|
* <p>
|
||||||
|
* To generate a <code>KeyFactory</code>, you need to supply an interface which
|
||||||
|
* describes the structure of the key. The interface should have a
|
||||||
|
* single method named <code>newInstance</code>, which returns an
|
||||||
|
* <code>Object</code>. The arguments array can be
|
||||||
|
* <i>anything</i>--Objects, primitive values, or single or
|
||||||
|
* multi-dimension arrays of either. For example:
|
||||||
|
* <p><pre>
|
||||||
|
* private interface IntStringKey {
|
||||||
|
* public Object newInstance(int i, String s);
|
||||||
|
* }
|
||||||
|
* </pre><p>
|
||||||
|
* Once you have made a <code>KeyFactory</code>, you generate a new key by calling
|
||||||
|
* the <code>newInstance</code> method defined by your interface.
|
||||||
|
* <p><pre>
|
||||||
|
* IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
|
||||||
|
* Object key1 = factory.newInstance(4, "Hello");
|
||||||
|
* Object key2 = factory.newInstance(4, "World");
|
||||||
|
* </pre><p>
|
||||||
|
* <b>Note:</b>
|
||||||
|
* <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
|
||||||
|
* <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
|
||||||
|
* @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
abstract public class KeyFactory {
|
||||||
|
|
||||||
|
private static final Signature GET_NAME =
|
||||||
|
TypeUtils.parseSignature("String getName()");
|
||||||
|
|
||||||
|
private static final Signature GET_CLASS =
|
||||||
|
TypeUtils.parseSignature("Class getClass()");
|
||||||
|
|
||||||
|
private static final Signature HASH_CODE =
|
||||||
|
TypeUtils.parseSignature("int hashCode()");
|
||||||
|
|
||||||
|
private static final Signature EQUALS =
|
||||||
|
TypeUtils.parseSignature("boolean equals(Object)");
|
||||||
|
|
||||||
|
private static final Signature TO_STRING =
|
||||||
|
TypeUtils.parseSignature("String toString()");
|
||||||
|
|
||||||
|
private static final Signature APPEND_STRING =
|
||||||
|
TypeUtils.parseSignature("StringBuffer append(String)");
|
||||||
|
|
||||||
|
private static final Type KEY_FACTORY =
|
||||||
|
TypeUtils.parseType("org.springframework.cglib.core.KeyFactory");
|
||||||
|
|
||||||
|
private static final Signature GET_SORT =
|
||||||
|
TypeUtils.parseSignature("int getSort()");
|
||||||
|
|
||||||
|
//generated numbers:
|
||||||
|
private final static int PRIMES[] = {
|
||||||
|
11, 73, 179, 331,
|
||||||
|
521, 787, 1213, 1823,
|
||||||
|
2609, 3691, 5189, 7247,
|
||||||
|
10037, 13931, 19289, 26627,
|
||||||
|
36683, 50441, 69403, 95401,
|
||||||
|
131129, 180179, 247501, 340057,
|
||||||
|
467063, 641371, 880603, 1209107,
|
||||||
|
1660097, 2279161, 3129011, 4295723,
|
||||||
|
5897291, 8095873, 11114263, 15257791,
|
||||||
|
20946017, 28754629, 39474179, 54189869,
|
||||||
|
74391461, 102123817, 140194277, 192456917,
|
||||||
|
264202273, 362693231, 497900099, 683510293,
|
||||||
|
938313161, 1288102441, 1768288259};
|
||||||
|
|
||||||
|
|
||||||
|
public static final Customizer CLASS_BY_NAME = new Customizer() {
|
||||||
|
public void customize(CodeEmitter e, Type type) {
|
||||||
|
if (type.equals(Constants.TYPE_CLASS)) {
|
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final FieldTypeCustomizer STORE_CLASS_AS_STRING = new FieldTypeCustomizer() {
|
||||||
|
public void customize(CodeEmitter e, int index, Type type) {
|
||||||
|
if (type.equals(Constants.TYPE_CLASS)) {
|
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Type getOutType(int index, Type type) {
|
||||||
|
if (type.equals(Constants.TYPE_CLASS)) {
|
||||||
|
return Constants.TYPE_STRING;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Type#hashCode()} is very expensive as it traverses full descriptor to calculate hash code.
|
||||||
|
* This customizer uses {@link Type#getSort()} as a hash code.
|
||||||
|
*/
|
||||||
|
public static final HashCodeCustomizer HASH_ASM_TYPE = new HashCodeCustomizer() {
|
||||||
|
public boolean customize(CodeEmitter e, Type type) {
|
||||||
|
if (Constants.TYPE_TYPE.equals(type)) {
|
||||||
|
e.invoke_virtual(type, GET_SORT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated this customizer might result in unexpected class leak since key object still holds a strong reference to the Object and class.
|
||||||
|
* It is recommended to have pre-processing method that would strip Objects and represent Classes as Strings
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static final Customizer OBJECT_BY_CLASS = new Customizer() {
|
||||||
|
public void customize(CodeEmitter e, Type type) {
|
||||||
|
e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected KeyFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyFactory create(Class keyInterface) {
|
||||||
|
return create(keyInterface, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyFactory create(Class keyInterface, Customizer customizer) {
|
||||||
|
return create(keyInterface.getClassLoader(), keyInterface, customizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyFactory create(Class keyInterface, KeyFactoryCustomizer first, List<KeyFactoryCustomizer> next) {
|
||||||
|
return create(keyInterface.getClassLoader(), keyInterface, first, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyFactory create(ClassLoader loader, Class keyInterface, Customizer customizer) {
|
||||||
|
return create(loader, keyInterface, customizer, Collections.<KeyFactoryCustomizer>emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
|
||||||
|
List<KeyFactoryCustomizer> next) {
|
||||||
|
Generator gen = new Generator();
|
||||||
|
gen.setInterface(keyInterface);
|
||||||
|
// SPRING PATCH BEGIN
|
||||||
|
gen.setContextClass(keyInterface);
|
||||||
|
// SPRING PATCH END
|
||||||
|
|
||||||
|
if (customizer != null) {
|
||||||
|
gen.addCustomizer(customizer);
|
||||||
|
}
|
||||||
|
if (next != null && !next.isEmpty()) {
|
||||||
|
for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
|
||||||
|
gen.addCustomizer(keyFactoryCustomizer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gen.setClassLoader(loader);
|
||||||
|
return gen.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Generator extends AbstractClassGenerator {
|
||||||
|
|
||||||
|
private static final Source SOURCE = new Source(KeyFactory.class.getName());
|
||||||
|
|
||||||
|
private static final Class[] KNOWN_CUSTOMIZER_TYPES = new Class[]{Customizer.class, FieldTypeCustomizer.class};
|
||||||
|
|
||||||
|
private Class keyInterface;
|
||||||
|
|
||||||
|
// TODO: Make me final when deprecated methods are removed
|
||||||
|
private CustomizerRegistry customizers = new CustomizerRegistry(KNOWN_CUSTOMIZER_TYPES);
|
||||||
|
|
||||||
|
private int constant;
|
||||||
|
|
||||||
|
private int multiplier;
|
||||||
|
|
||||||
|
public Generator() {
|
||||||
|
super(SOURCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() {
|
||||||
|
return keyInterface.getClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() {
|
||||||
|
return ReflectUtils.getProtectionDomain(keyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #addCustomizer(KeyFactoryCustomizer)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void setCustomizer(Customizer customizer) {
|
||||||
|
customizers = CustomizerRegistry.singleton(customizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCustomizer(KeyFactoryCustomizer customizer) {
|
||||||
|
customizers.add(customizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<T> getCustomizers(Class<T> klass) {
|
||||||
|
return customizers.get(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterface(Class keyInterface) {
|
||||||
|
this.keyInterface = keyInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyFactory create() {
|
||||||
|
setNamePrefix(keyInterface.getName());
|
||||||
|
return (KeyFactory) super.create(keyInterface.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHashConstant(int constant) {
|
||||||
|
this.constant = constant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHashMultiplier(int multiplier) {
|
||||||
|
this.multiplier = multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object firstInstance(Class type) {
|
||||||
|
return ReflectUtils.newInstance(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object nextInstance(Object instance) {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) {
|
||||||
|
ClassEmitter ce = new ClassEmitter(v);
|
||||||
|
|
||||||
|
Method newInstance = ReflectUtils.findNewInstance(keyInterface);
|
||||||
|
if (!newInstance.getReturnType().equals(Object.class)) {
|
||||||
|
throw new IllegalArgumentException("newInstance method must return Object");
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
|
||||||
|
ce.begin_class(Constants.V1_2,
|
||||||
|
Constants.ACC_PUBLIC,
|
||||||
|
getClassName(),
|
||||||
|
KEY_FACTORY,
|
||||||
|
new Type[]{Type.getType(keyInterface)},
|
||||||
|
Constants.SOURCE_FILE);
|
||||||
|
EmitUtils.null_constructor(ce);
|
||||||
|
EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
|
||||||
|
|
||||||
|
int seed = 0;
|
||||||
|
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
|
||||||
|
TypeUtils.parseConstructor(parameterTypes),
|
||||||
|
null);
|
||||||
|
e.load_this();
|
||||||
|
e.super_invoke_constructor();
|
||||||
|
e.load_this();
|
||||||
|
List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class);
|
||||||
|
for (int i = 0; i < parameterTypes.length; i++) {
|
||||||
|
Type parameterType = parameterTypes[i];
|
||||||
|
Type fieldType = parameterType;
|
||||||
|
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
|
||||||
|
fieldType = customizer.getOutType(i, fieldType);
|
||||||
|
}
|
||||||
|
seed += fieldType.hashCode();
|
||||||
|
ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
|
||||||
|
getFieldName(i),
|
||||||
|
fieldType,
|
||||||
|
null);
|
||||||
|
e.dup();
|
||||||
|
e.load_arg(i);
|
||||||
|
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
|
||||||
|
customizer.customize(e, i, parameterType);
|
||||||
|
}
|
||||||
|
e.putfield(getFieldName(i));
|
||||||
|
}
|
||||||
|
e.return_value();
|
||||||
|
e.end_method();
|
||||||
|
|
||||||
|
// hash code
|
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);
|
||||||
|
int hc = (constant != 0) ? constant : PRIMES[(Math.abs(seed) % PRIMES.length)];
|
||||||
|
int hm = (multiplier != 0) ? multiplier : PRIMES[(Math.abs(seed * 13) % PRIMES.length)];
|
||||||
|
e.push(hc);
|
||||||
|
for (int i = 0; i < parameterTypes.length; i++) {
|
||||||
|
e.load_this();
|
||||||
|
e.getfield(getFieldName(i));
|
||||||
|
EmitUtils.hash_code(e, parameterTypes[i], hm, customizers);
|
||||||
|
}
|
||||||
|
e.return_value();
|
||||||
|
e.end_method();
|
||||||
|
|
||||||
|
// equals
|
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);
|
||||||
|
Label fail = e.make_label();
|
||||||
|
e.load_arg(0);
|
||||||
|
e.instance_of_this();
|
||||||
|
e.if_jump(CodeEmitter.EQ, fail);
|
||||||
|
for (int i = 0; i < parameterTypes.length; i++) {
|
||||||
|
e.load_this();
|
||||||
|
e.getfield(getFieldName(i));
|
||||||
|
e.load_arg(0);
|
||||||
|
e.checkcast_this();
|
||||||
|
e.getfield(getFieldName(i));
|
||||||
|
EmitUtils.not_equals(e, parameterTypes[i], fail, customizers);
|
||||||
|
}
|
||||||
|
e.push(1);
|
||||||
|
e.return_value();
|
||||||
|
e.mark(fail);
|
||||||
|
e.push(0);
|
||||||
|
e.return_value();
|
||||||
|
e.end_method();
|
||||||
|
|
||||||
|
// toString
|
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);
|
||||||
|
e.new_instance(Constants.TYPE_STRING_BUFFER);
|
||||||
|
e.dup();
|
||||||
|
e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
|
||||||
|
for (int i = 0; i < parameterTypes.length; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
e.push(", ");
|
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
|
||||||
|
}
|
||||||
|
e.load_this();
|
||||||
|
e.getfield(getFieldName(i));
|
||||||
|
EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers);
|
||||||
|
}
|
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
|
||||||
|
e.return_value();
|
||||||
|
e.end_method();
|
||||||
|
|
||||||
|
ce.end_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFieldName(int arg) {
|
||||||
|
return "FIELD_" + arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,617 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2003,2004 The Apache Software Foundation
|
||||||
|
*
|
||||||
|
* 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.cglib.core;
|
||||||
|
|
||||||
|
import java.beans.BeanInfo;
|
||||||
|
import java.beans.IntrospectionException;
|
||||||
|
import java.beans.Introspector;
|
||||||
|
import java.beans.PropertyDescriptor;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Member;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.asm.Attribute;
|
||||||
|
import org.springframework.asm.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version $Id: ReflectUtils.java,v 1.30 2009/01/11 19:47:49 herbyderby Exp $
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
public class ReflectUtils {
|
||||||
|
|
||||||
|
private ReflectUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map primitives = new HashMap(8);
|
||||||
|
|
||||||
|
private static final Map transforms = new HashMap(8);
|
||||||
|
|
||||||
|
private static final ClassLoader defaultLoader = ReflectUtils.class.getClassLoader();
|
||||||
|
|
||||||
|
// SPRING PATCH BEGIN
|
||||||
|
private static final Method privateLookupInMethod;
|
||||||
|
|
||||||
|
private static final Method lookupDefineClassMethod;
|
||||||
|
|
||||||
|
private static final Method classLoaderDefineClassMethod;
|
||||||
|
|
||||||
|
private static final ProtectionDomain PROTECTION_DOMAIN;
|
||||||
|
|
||||||
|
private static final Throwable THROWABLE;
|
||||||
|
|
||||||
|
private static final List<Method> OBJECT_METHODS = new ArrayList<Method>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
Method privateLookupIn;
|
||||||
|
Method lookupDefineClass;
|
||||||
|
Method classLoaderDefineClass;
|
||||||
|
ProtectionDomain protectionDomain;
|
||||||
|
Throwable throwable = null;
|
||||||
|
try {
|
||||||
|
privateLookupIn = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||||
|
public Object run() throws Exception {
|
||||||
|
try {
|
||||||
|
return MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lookupDefineClass = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||||
|
public Object run() throws Exception {
|
||||||
|
try {
|
||||||
|
return MethodHandles.Lookup.class.getMethod("defineClass", byte[].class);
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
classLoaderDefineClass = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||||
|
public Object run() throws Exception {
|
||||||
|
return ClassLoader.class.getDeclaredMethod("defineClass",
|
||||||
|
String.class, byte[].class, Integer.TYPE, Integer.TYPE, ProtectionDomain.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
protectionDomain = getProtectionDomain(ReflectUtils.class);
|
||||||
|
AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||||
|
public Object run() throws Exception {
|
||||||
|
Method[] methods = Object.class.getDeclaredMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
if ("finalize".equals(method.getName())
|
||||||
|
|| (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OBJECT_METHODS.add(method);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
privateLookupIn = null;
|
||||||
|
lookupDefineClass = null;
|
||||||
|
classLoaderDefineClass = null;
|
||||||
|
protectionDomain = null;
|
||||||
|
throwable = t;
|
||||||
|
}
|
||||||
|
privateLookupInMethod = privateLookupIn;
|
||||||
|
lookupDefineClassMethod = lookupDefineClass;
|
||||||
|
classLoaderDefineClassMethod = classLoaderDefineClass;
|
||||||
|
PROTECTION_DOMAIN = protectionDomain;
|
||||||
|
THROWABLE = throwable;
|
||||||
|
}
|
||||||
|
// SPRING PATCH END
|
||||||
|
|
||||||
|
private static final String[] CGLIB_PACKAGES = {
|
||||||
|
"java.lang",
|
||||||
|
};
|
||||||
|
|
||||||
|
static {
|
||||||
|
primitives.put("byte", Byte.TYPE);
|
||||||
|
primitives.put("char", Character.TYPE);
|
||||||
|
primitives.put("double", Double.TYPE);
|
||||||
|
primitives.put("float", Float.TYPE);
|
||||||
|
primitives.put("int", Integer.TYPE);
|
||||||
|
primitives.put("long", Long.TYPE);
|
||||||
|
primitives.put("short", Short.TYPE);
|
||||||
|
primitives.put("boolean", Boolean.TYPE);
|
||||||
|
|
||||||
|
transforms.put("byte", "B");
|
||||||
|
transforms.put("char", "C");
|
||||||
|
transforms.put("double", "D");
|
||||||
|
transforms.put("float", "F");
|
||||||
|
transforms.put("int", "I");
|
||||||
|
transforms.put("long", "J");
|
||||||
|
transforms.put("short", "S");
|
||||||
|
transforms.put("boolean", "Z");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProtectionDomain getProtectionDomain(final Class source) {
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (ProtectionDomain) AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
return source.getProtectionDomain();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type[] getExceptionTypes(Member member) {
|
||||||
|
if (member instanceof Method) {
|
||||||
|
return TypeUtils.getTypes(((Method) member).getExceptionTypes());
|
||||||
|
}
|
||||||
|
else if (member instanceof Constructor) {
|
||||||
|
return TypeUtils.getTypes(((Constructor) member).getExceptionTypes());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Cannot get exception types of a field");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Signature getSignature(Member member) {
|
||||||
|
if (member instanceof Method) {
|
||||||
|
return new Signature(member.getName(), Type.getMethodDescriptor((Method) member));
|
||||||
|
}
|
||||||
|
else if (member instanceof Constructor) {
|
||||||
|
Type[] types = TypeUtils.getTypes(((Constructor) member).getParameterTypes());
|
||||||
|
return new Signature(Constants.CONSTRUCTOR_NAME,
|
||||||
|
Type.getMethodDescriptor(Type.VOID_TYPE, types));
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Cannot get signature of a field");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Constructor findConstructor(String desc) {
|
||||||
|
return findConstructor(desc, defaultLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Constructor findConstructor(String desc, ClassLoader loader) {
|
||||||
|
try {
|
||||||
|
int lparen = desc.indexOf('(');
|
||||||
|
String className = desc.substring(0, lparen).trim();
|
||||||
|
return getClass(className, loader).getConstructor(parseTypes(desc, loader));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException | NoSuchMethodException ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Method findMethod(String desc) {
|
||||||
|
return findMethod(desc, defaultLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Method findMethod(String desc, ClassLoader loader) {
|
||||||
|
try {
|
||||||
|
int lparen = desc.indexOf('(');
|
||||||
|
int dot = desc.lastIndexOf('.', lparen);
|
||||||
|
String className = desc.substring(0, dot).trim();
|
||||||
|
String methodName = desc.substring(dot + 1, lparen).trim();
|
||||||
|
return getClass(className, loader).getDeclaredMethod(methodName, parseTypes(desc, loader));
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException | NoSuchMethodException ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class[] parseTypes(String desc, ClassLoader loader) throws ClassNotFoundException {
|
||||||
|
int lparen = desc.indexOf('(');
|
||||||
|
int rparen = desc.indexOf(')', lparen);
|
||||||
|
List params = new ArrayList();
|
||||||
|
int start = lparen + 1;
|
||||||
|
for (; ; ) {
|
||||||
|
int comma = desc.indexOf(',', start);
|
||||||
|
if (comma < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
params.add(desc.substring(start, comma).trim());
|
||||||
|
start = comma + 1;
|
||||||
|
}
|
||||||
|
if (start < rparen) {
|
||||||
|
params.add(desc.substring(start, rparen).trim());
|
||||||
|
}
|
||||||
|
Class[] types = new Class[params.size()];
|
||||||
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
types[i] = getClass((String) params.get(i), loader);
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class getClass(String className, ClassLoader loader) throws ClassNotFoundException {
|
||||||
|
return getClass(className, loader, CGLIB_PACKAGES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class getClass(String className, ClassLoader loader, String[] packages) throws ClassNotFoundException {
|
||||||
|
String save = className;
|
||||||
|
int dimensions = 0;
|
||||||
|
int index = 0;
|
||||||
|
while ((index = className.indexOf("[]", index) + 1) > 0) {
|
||||||
|
dimensions++;
|
||||||
|
}
|
||||||
|
StringBuffer brackets = new StringBuffer(className.length() - dimensions);
|
||||||
|
for (int i = 0; i < dimensions; i++) {
|
||||||
|
brackets.append('[');
|
||||||
|
}
|
||||||
|
className = className.substring(0, className.length() - 2 * dimensions);
|
||||||
|
|
||||||
|
String prefix = (dimensions > 0) ? brackets + "L" : "";
|
||||||
|
String suffix = (dimensions > 0) ? ";" : "";
|
||||||
|
try {
|
||||||
|
return Class.forName(prefix + className + suffix, false, loader);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ignore) {
|
||||||
|
}
|
||||||
|
for (int i = 0; i < packages.length; i++) {
|
||||||
|
try {
|
||||||
|
return Class.forName(prefix + packages[i] + '.' + className + suffix, false, loader);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dimensions == 0) {
|
||||||
|
Class c = (Class) primitives.get(className);
|
||||||
|
if (c != null) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String transform = (String) transforms.get(className);
|
||||||
|
if (transform != null) {
|
||||||
|
try {
|
||||||
|
return Class.forName(brackets + transform, false, loader);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ClassNotFoundException(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object newInstance(Class type) {
|
||||||
|
return newInstance(type, Constants.EMPTY_CLASS_ARRAY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object newInstance(Class type, Class[] parameterTypes, Object[] args) {
|
||||||
|
return newInstance(getConstructor(type, parameterTypes), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") // on JDK 9
|
||||||
|
public static Object newInstance(final Constructor cstruct, final Object[] args) {
|
||||||
|
boolean flag = cstruct.isAccessible();
|
||||||
|
try {
|
||||||
|
if (!flag) {
|
||||||
|
cstruct.setAccessible(true);
|
||||||
|
}
|
||||||
|
Object result = cstruct.newInstance(args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (InstantiationException e) {
|
||||||
|
throw new CodeGenerationException(e);
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e) {
|
||||||
|
throw new CodeGenerationException(e);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
throw new CodeGenerationException(e.getTargetException());
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (!flag) {
|
||||||
|
cstruct.setAccessible(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Constructor getConstructor(Class type, Class[] parameterTypes) {
|
||||||
|
try {
|
||||||
|
Constructor constructor = type.getDeclaredConstructor(parameterTypes);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
throw new CodeGenerationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getNames(Class[] classes) {
|
||||||
|
if (classes == null)
|
||||||
|
return null;
|
||||||
|
String[] names = new String[classes.length];
|
||||||
|
for (int i = 0; i < names.length; i++) {
|
||||||
|
names[i] = classes[i].getName();
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class[] getClasses(Object[] objects) {
|
||||||
|
Class[] classes = new Class[objects.length];
|
||||||
|
for (int i = 0; i < objects.length; i++) {
|
||||||
|
classes[i] = objects[i].getClass();
|
||||||
|
}
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Method findNewInstance(Class iface) {
|
||||||
|
Method m = findInterfaceMethod(iface);
|
||||||
|
if (!m.getName().equals("newInstance")) {
|
||||||
|
throw new IllegalArgumentException(iface + " missing newInstance method");
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Method[] getPropertyMethods(PropertyDescriptor[] properties, boolean read, boolean write) {
|
||||||
|
Set methods = new HashSet();
|
||||||
|
for (int i = 0; i < properties.length; i++) {
|
||||||
|
PropertyDescriptor pd = properties[i];
|
||||||
|
if (read) {
|
||||||
|
methods.add(pd.getReadMethod());
|
||||||
|
}
|
||||||
|
if (write) {
|
||||||
|
methods.add(pd.getWriteMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
methods.remove(null);
|
||||||
|
return (Method[]) methods.toArray(new Method[methods.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyDescriptor[] getBeanProperties(Class type) {
|
||||||
|
return getPropertiesHelper(type, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyDescriptor[] getBeanGetters(Class type) {
|
||||||
|
return getPropertiesHelper(type, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyDescriptor[] getBeanSetters(Class type) {
|
||||||
|
return getPropertiesHelper(type, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PropertyDescriptor[] getPropertiesHelper(Class type, boolean read, boolean write) {
|
||||||
|
try {
|
||||||
|
BeanInfo info = Introspector.getBeanInfo(type, Object.class);
|
||||||
|
PropertyDescriptor[] all = info.getPropertyDescriptors();
|
||||||
|
if (read && write) {
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
List properties = new ArrayList(all.length);
|
||||||
|
for (int i = 0; i < all.length; i++) {
|
||||||
|
PropertyDescriptor pd = all[i];
|
||||||
|
if ((read && pd.getReadMethod() != null) ||
|
||||||
|
(write && pd.getWriteMethod() != null)) {
|
||||||
|
properties.add(pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (PropertyDescriptor[]) properties.toArray(new PropertyDescriptor[properties.size()]);
|
||||||
|
}
|
||||||
|
catch (IntrospectionException e) {
|
||||||
|
throw new CodeGenerationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Method findDeclaredMethod(final Class type,
|
||||||
|
final String methodName, final Class[] parameterTypes)
|
||||||
|
throws NoSuchMethodException {
|
||||||
|
|
||||||
|
Class cl = type;
|
||||||
|
while (cl != null) {
|
||||||
|
try {
|
||||||
|
return cl.getDeclaredMethod(methodName, parameterTypes);
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException e) {
|
||||||
|
cl = cl.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NoSuchMethodException(methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List addAllMethods(final Class type, final List list) {
|
||||||
|
if (type == Object.class) {
|
||||||
|
list.addAll(OBJECT_METHODS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
list.addAll(java.util.Arrays.asList(type.getDeclaredMethods()));
|
||||||
|
|
||||||
|
Class superclass = type.getSuperclass();
|
||||||
|
if (superclass != null) {
|
||||||
|
addAllMethods(superclass, list);
|
||||||
|
}
|
||||||
|
Class[] interfaces = type.getInterfaces();
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
addAllMethods(interfaces[i], list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List addAllInterfaces(Class type, List list) {
|
||||||
|
Class superclass = type.getSuperclass();
|
||||||
|
if (superclass != null) {
|
||||||
|
list.addAll(Arrays.asList(type.getInterfaces()));
|
||||||
|
addAllInterfaces(superclass, list);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Method findInterfaceMethod(Class iface) {
|
||||||
|
if (!iface.isInterface()) {
|
||||||
|
throw new IllegalArgumentException(iface + " is not an interface");
|
||||||
|
}
|
||||||
|
Method[] methods = iface.getDeclaredMethods();
|
||||||
|
if (methods.length != 1) {
|
||||||
|
throw new IllegalArgumentException("expecting exactly 1 method in " + iface);
|
||||||
|
}
|
||||||
|
return methods[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPRING PATCH BEGIN
|
||||||
|
public static Class defineClass(String className, byte[] b, ClassLoader loader) throws Exception {
|
||||||
|
return defineClass(className, b, loader, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class defineClass(String className, byte[] b, ClassLoader loader,
|
||||||
|
ProtectionDomain protectionDomain) throws Exception {
|
||||||
|
|
||||||
|
return defineClass(className, b, loader, protectionDomain, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") // on JDK 9
|
||||||
|
public static Class defineClass(String className, byte[] b, ClassLoader loader,
|
||||||
|
ProtectionDomain protectionDomain, Class<?> contextClass) throws Exception {
|
||||||
|
|
||||||
|
Class c = null;
|
||||||
|
if (contextClass != null && privateLookupInMethod != null && lookupDefineClassMethod != null) {
|
||||||
|
try {
|
||||||
|
MethodHandles.Lookup lookup =
|
||||||
|
(MethodHandles.Lookup) privateLookupInMethod.invoke(null, contextClass, MethodHandles.lookup());
|
||||||
|
c = (Class) lookupDefineClassMethod.invoke(lookup, b);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException ex) {
|
||||||
|
if (!(ex.getTargetException() instanceof IllegalArgumentException)) {
|
||||||
|
throw new CodeGenerationException(ex.getTargetException());
|
||||||
|
}
|
||||||
|
// in case of IllegalArgumentException: fall through to defineClass
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (protectionDomain == null) {
|
||||||
|
protectionDomain = PROTECTION_DOMAIN;
|
||||||
|
}
|
||||||
|
if (c == null) {
|
||||||
|
if (classLoaderDefineClassMethod != null) {
|
||||||
|
Object[] args = new Object[]{className, b, 0, b.length, protectionDomain};
|
||||||
|
try {
|
||||||
|
if (!classLoaderDefineClassMethod.isAccessible()) {
|
||||||
|
classLoaderDefineClassMethod.setAccessible(true);
|
||||||
|
}
|
||||||
|
c = (Class) classLoaderDefineClassMethod.invoke(loader, args);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException ex) {
|
||||||
|
throw new CodeGenerationException(ex.getTargetException());
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new CodeGenerationException(THROWABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Force static initializers to run.
|
||||||
|
Class.forName(className, true, loader);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
// SPRING PATCH END
|
||||||
|
|
||||||
|
public static int findPackageProtected(Class[] classes) {
|
||||||
|
for (int i = 0; i < classes.length; i++) {
|
||||||
|
if (!Modifier.isPublic(classes[i].getModifiers())) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo getMethodInfo(final Member member, final int modifiers) {
|
||||||
|
final Signature sig = getSignature(member);
|
||||||
|
return new MethodInfo() {
|
||||||
|
private ClassInfo ci;
|
||||||
|
|
||||||
|
public ClassInfo getClassInfo() {
|
||||||
|
if (ci == null)
|
||||||
|
ci = ReflectUtils.getClassInfo(member.getDeclaringClass());
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getModifiers() {
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Signature getSignature() {
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type[] getExceptionTypes() {
|
||||||
|
return ReflectUtils.getExceptionTypes(member);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attribute getAttribute() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo getMethodInfo(Member member) {
|
||||||
|
return getMethodInfo(member, member.getModifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassInfo getClassInfo(final Class clazz) {
|
||||||
|
final Type type = Type.getType(clazz);
|
||||||
|
final Type sc = (clazz.getSuperclass() == null) ? null : Type.getType(clazz.getSuperclass());
|
||||||
|
return new ClassInfo() {
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
public Type getSuperType() {
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
public Type[] getInterfaces() {
|
||||||
|
return TypeUtils.getTypes(clazz.getInterfaces());
|
||||||
|
}
|
||||||
|
public int getModifiers() {
|
||||||
|
return clazz.getModifiers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by MethodInterceptorGenerated generated code
|
||||||
|
public static Method[] findMethods(String[] namesAndDescriptors, Method[] methods) {
|
||||||
|
Map map = new HashMap();
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
Method method = methods[i];
|
||||||
|
map.put(method.getName() + Type.getMethodDescriptor(method), method);
|
||||||
|
}
|
||||||
|
Method[] result = new Method[namesAndDescriptors.length / 2];
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = (Method) map.get(namesAndDescriptors[i * 2] + namesAndDescriptors[i * 2 + 1]);
|
||||||
|
if (result[i] == null) {
|
||||||
|
// TODO: error?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* Spring's repackaging of the
|
||||||
|
* <a href="http://cglib.sourceforge.net">CGLIB</a> core package
|
||||||
|
* (for internal use only).
|
||||||
|
*
|
||||||
|
* <p>As this repackaging happens at the class file level, sources
|
||||||
|
* and javadocs are not available here... except for a few files
|
||||||
|
* that have been patched for Spring's purposes on JDK 9/10/11.
|
||||||
|
*/
|
||||||
|
package org.springframework.cglib.core;
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,251 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2003,2004 The Apache Software Foundation
|
||||||
|
*
|
||||||
|
* 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.cglib.proxy;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.springframework.cglib.core.AbstractClassGenerator;
|
||||||
|
import org.springframework.cglib.core.CodeGenerationException;
|
||||||
|
import org.springframework.cglib.core.GeneratorStrategy;
|
||||||
|
import org.springframework.cglib.core.NamingPolicy;
|
||||||
|
import org.springframework.cglib.core.Signature;
|
||||||
|
import org.springframework.cglib.reflect.FastClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classes generated by {@link Enhancer} pass this object to the
|
||||||
|
* registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can
|
||||||
|
* be used to either invoke the original method, or call the same method on a different
|
||||||
|
* object of the same type.
|
||||||
|
* @version $Id: MethodProxy.java,v 1.16 2009/01/11 20:09:48 herbyderby Exp $
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
public class MethodProxy {
|
||||||
|
|
||||||
|
private Signature sig1;
|
||||||
|
|
||||||
|
private Signature sig2;
|
||||||
|
|
||||||
|
private CreateInfo createInfo;
|
||||||
|
|
||||||
|
private final Object initLock = new Object();
|
||||||
|
|
||||||
|
private volatile FastClassInfo fastClassInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For internal use by {@link Enhancer} only; see the {@link org.springframework.cglib.reflect.FastMethod} class
|
||||||
|
* for similar functionality.
|
||||||
|
*/
|
||||||
|
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
|
||||||
|
MethodProxy proxy = new MethodProxy();
|
||||||
|
proxy.sig1 = new Signature(name1, desc);
|
||||||
|
proxy.sig2 = new Signature(name2, desc);
|
||||||
|
proxy.createInfo = new CreateInfo(c1, c2);
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
/*
|
||||||
|
* Using a volatile invariant allows us to initialize the FastClass and
|
||||||
|
* method index pairs atomically.
|
||||||
|
*
|
||||||
|
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this
|
||||||
|
* code could allow fastClassInfo to be instantiated more than once, which
|
||||||
|
* appears to be benign.
|
||||||
|
*/
|
||||||
|
if (fastClassInfo == null) {
|
||||||
|
synchronized (initLock) {
|
||||||
|
if (fastClassInfo == null) {
|
||||||
|
CreateInfo ci = createInfo;
|
||||||
|
|
||||||
|
FastClassInfo fci = new FastClassInfo();
|
||||||
|
fci.f1 = helper(ci, ci.c1);
|
||||||
|
fci.f2 = helper(ci, ci.c2);
|
||||||
|
fci.i1 = fci.f1.getIndex(sig1);
|
||||||
|
fci.i2 = fci.f2.getIndex(sig2);
|
||||||
|
fastClassInfo = fci;
|
||||||
|
createInfo = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class FastClassInfo {
|
||||||
|
|
||||||
|
FastClass f1;
|
||||||
|
|
||||||
|
FastClass f2;
|
||||||
|
|
||||||
|
int i1;
|
||||||
|
|
||||||
|
int i2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class CreateInfo {
|
||||||
|
|
||||||
|
Class c1;
|
||||||
|
|
||||||
|
Class c2;
|
||||||
|
|
||||||
|
NamingPolicy namingPolicy;
|
||||||
|
|
||||||
|
GeneratorStrategy strategy;
|
||||||
|
|
||||||
|
boolean attemptLoad;
|
||||||
|
|
||||||
|
public CreateInfo(Class c1, Class c2) {
|
||||||
|
this.c1 = c1;
|
||||||
|
this.c2 = c2;
|
||||||
|
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
|
||||||
|
if (fromEnhancer != null) {
|
||||||
|
namingPolicy = fromEnhancer.getNamingPolicy();
|
||||||
|
strategy = fromEnhancer.getStrategy();
|
||||||
|
attemptLoad = fromEnhancer.getAttemptLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static FastClass helper(CreateInfo ci, Class type) {
|
||||||
|
FastClass.Generator g = new FastClass.Generator();
|
||||||
|
g.setType(type);
|
||||||
|
// SPRING PATCH BEGIN
|
||||||
|
g.setContextClass(type);
|
||||||
|
// SPRING PATCH END
|
||||||
|
g.setClassLoader(ci.c2.getClassLoader());
|
||||||
|
g.setNamingPolicy(ci.namingPolicy);
|
||||||
|
g.setStrategy(ci.strategy);
|
||||||
|
g.setAttemptLoad(ci.attemptLoad);
|
||||||
|
return g.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodProxy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the signature of the proxied method.
|
||||||
|
*/
|
||||||
|
public Signature getSignature() {
|
||||||
|
return sig1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the synthetic method created by CGLIB which is
|
||||||
|
* used by {@link #invokeSuper} to invoke the superclass
|
||||||
|
* (non-intercepted) method implementation. The parameter types are
|
||||||
|
* the same as the proxied method.
|
||||||
|
*/
|
||||||
|
public String getSuperName() {
|
||||||
|
return sig2.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link org.springframework.cglib.reflect.FastClass} method index
|
||||||
|
* for the method used by {@link #invokeSuper}. This index uniquely
|
||||||
|
* identifies the method within the generated proxy, and therefore
|
||||||
|
* can be useful to reference external metadata.
|
||||||
|
* @see #getSuperName
|
||||||
|
*/
|
||||||
|
public int getSuperIndex() {
|
||||||
|
init();
|
||||||
|
return fastClassInfo.i2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing
|
||||||
|
FastClass getFastClass() {
|
||||||
|
init();
|
||||||
|
return fastClassInfo.f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing
|
||||||
|
FastClass getSuperFastClass() {
|
||||||
|
init();
|
||||||
|
return fastClassInfo.f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the <code>MethodProxy</code> used when intercepting the method
|
||||||
|
* matching the given signature.
|
||||||
|
* @param type the class generated by Enhancer
|
||||||
|
* @param sig the signature to match
|
||||||
|
* @return the MethodProxy instance, or null if no applicable matching method is found
|
||||||
|
* @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor
|
||||||
|
*/
|
||||||
|
public static MethodProxy find(Class type, Signature sig) {
|
||||||
|
try {
|
||||||
|
Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME,
|
||||||
|
MethodInterceptorGenerator.FIND_PROXY_TYPES);
|
||||||
|
return (MethodProxy) m.invoke(null, new Object[]{sig});
|
||||||
|
}
|
||||||
|
catch (NoSuchMethodException ex) {
|
||||||
|
throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException | InvocationTargetException ex) {
|
||||||
|
throw new CodeGenerationException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the original method, on a different object of the same type.
|
||||||
|
* @param obj the compatible object; recursion will result if you use the object passed as the first
|
||||||
|
* argument to the MethodInterceptor (usually not what you want)
|
||||||
|
* @param args the arguments passed to the intercepted method; you may substitute a different
|
||||||
|
* argument array as long as the types are compatible
|
||||||
|
* @throws Throwable the bare exceptions thrown by the called method are passed through
|
||||||
|
* without wrapping in an <code>InvocationTargetException</code>
|
||||||
|
* @see MethodInterceptor#intercept
|
||||||
|
*/
|
||||||
|
public Object invoke(Object obj, Object[] args) throws Throwable {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
FastClassInfo fci = fastClassInfo;
|
||||||
|
return fci.f1.invoke(fci.i1, obj, args);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException ex) {
|
||||||
|
throw ex.getTargetException();
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException ex) {
|
||||||
|
if (fastClassInfo.i1 < 0)
|
||||||
|
throw new IllegalArgumentException("Protected method: " + sig1);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the original (super) method on the specified object.
|
||||||
|
* @param obj the enhanced object, must be the object passed as the first
|
||||||
|
* argument to the MethodInterceptor
|
||||||
|
* @param args the arguments passed to the intercepted method; you may substitute a different
|
||||||
|
* argument array as long as the types are compatible
|
||||||
|
* @throws Throwable the bare exceptions thrown by the called method are passed through
|
||||||
|
* without wrapping in an <code>InvocationTargetException</code>
|
||||||
|
* @see MethodInterceptor#intercept
|
||||||
|
*/
|
||||||
|
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
FastClassInfo fci = fastClassInfo;
|
||||||
|
return fci.f2.invoke(fci.i2, obj, args);
|
||||||
|
}
|
||||||
|
catch (InvocationTargetException e) {
|
||||||
|
throw e.getTargetException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* Spring's repackaging of the
|
||||||
|
* <a href="http://cglib.sourceforge.net">CGLIB</a> proxy package
|
||||||
|
* (for internal use only).
|
||||||
|
*
|
||||||
|
* <p>As this repackaging happens at the class file level, sources
|
||||||
|
* and javadocs are not available here... except for a few files
|
||||||
|
* that have been patched for Spring's purposes on JDK 9/10/11.
|
||||||
|
*/
|
||||||
|
package org.springframework.cglib.proxy;
|
||||||
Loading…
Reference in New Issue