diff --git a/org.springframework.aspects/.classpath b/org.springframework.aspects/.classpath index 8b4c6992f5..b650717c2e 100644 --- a/org.springframework.aspects/.classpath +++ b/org.springframework.aspects/.classpath @@ -1,15 +1,19 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.aspects/build.xml b/org.springframework.aspects/build.xml index 98488bc099..bab62bd033 100644 --- a/org.springframework.aspects/build.xml +++ b/org.springframework.aspects/build.xml @@ -3,4 +3,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.aspects/ivy.xml b/org.springframework.aspects/ivy.xml index 5bd5219b48..ae5786d640 100644 --- a/org.springframework.aspects/ivy.xml +++ b/org.springframework.aspects/ivy.xml @@ -22,9 +22,14 @@ - - + + + + + + + diff --git a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java new file mode 100644 index 0000000000..d593e1d118 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import junit.framework.TestCase; + +/** + * @author Adrian Colyer + */ +public class AutoProxyWithCodeStyleAspectsTests extends TestCase { + + public void testNoAutoproxyingOfAjcCompiledAspects() { + new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml"); + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj new file mode 100644 index 0000000000..bf16e144a9 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +import org.aspectj.lang.annotation.Aspect; + +/** + * @author Adrian Colyer + */ +@Aspect +public aspect CodeStyleAspect { + + private String foo; + + pointcut somePC() : call(* someMethod()); + + before() : somePC() { + System.out.println("match"); + } + + public void setFoo(String foo) { + this.foo = foo; + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml new file mode 100644 index 0000000000..4af6ec7968 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/Colour.java b/org.springframework.aspects/src/test/java/org/springframework/beans/Colour.java new file mode 100644 index 0000000000..60dc333e0b --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/Colour.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import org.springframework.core.enums.ShortCodedLabeledEnum; + +/** + * @author Rob Harrop + */ +public class Colour extends ShortCodedLabeledEnum { + + public static final Colour RED = new Colour(0, "RED"); + public static final Colour BLUE = new Colour(1, "BLUE"); + public static final Colour GREEN = new Colour(2, "GREEN"); + public static final Colour PURPLE = new Colour(3, "PURPLE"); + + private Colour(int code, String label) { + super(code, label); + } + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/DerivedTestBean.java b/org.springframework.aspects/src/test/java/org/springframework/beans/DerivedTestBean.java new file mode 100644 index 0000000000..2bb41a9d5b --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/DerivedTestBean.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.Serializable; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; + +/** + * @author Juergen Hoeller + * @since 21.08.2003 + */ +public class DerivedTestBean extends TestBean implements Serializable, BeanNameAware, DisposableBean { + + private String beanName; + + private boolean initialized; + + private boolean destroyed; + + + public DerivedTestBean() { + } + + public DerivedTestBean(String[] names) { + if (names == null || names.length < 2) { + throw new IllegalArgumentException("Invalid names array"); + } + setName(names[0]); + setBeanName(names[1]); + } + + public static DerivedTestBean create(String[] names) { + return new DerivedTestBean(names); + } + + + public void setBeanName(String beanName) { + if (this.beanName == null || beanName == null) { + this.beanName = beanName; + } + } + + public String getBeanName() { + return beanName; + } + + public void setSpouseRef(String name) { + setSpouse(new TestBean(name)); + } + + + public void initialize() { + this.initialized = true; + } + + public boolean wasInitialized() { + return initialized; + } + + + public void destroy() { + this.destroyed = true; + } + + public boolean wasDestroyed() { + return destroyed; + } + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/INestedTestBean.java b/org.springframework.aspects/src/test/java/org/springframework/beans/INestedTestBean.java new file mode 100644 index 0000000000..7d87547b5f --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/INestedTestBean.java @@ -0,0 +1,23 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +public interface INestedTestBean { + + public String getCompany(); + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/IOther.java b/org.springframework.aspects/src/test/java/org/springframework/beans/IOther.java new file mode 100644 index 0000000000..797486ec44 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/IOther.java @@ -0,0 +1,24 @@ + +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +public interface IOther { + + void absquatulate(); + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/ITestBean.java b/org.springframework.aspects/src/test/java/org/springframework/beans/ITestBean.java new file mode 100644 index 0000000000..cdf5ef510d --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/ITestBean.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.IOException; + +/** + * Interface used for {@link org.springframework.beans.TestBean}. + * + *

Two methods are the same as on Person, but if this + * extends person it breaks quite a few tests.. + * + * @author Rod Johnson + * @author Juergen Hoeller + */ +public interface ITestBean { + + int getAge(); + + void setAge(int age); + + String getName(); + + void setName(String name); + + ITestBean getSpouse(); + + void setSpouse(ITestBean spouse); + + ITestBean[] getSpouses(); + + String[] getStringArray(); + + void setStringArray(String[] stringArray); + + /** + * Throws a given (non-null) exception. + */ + void exceptional(Throwable t) throws Throwable; + + Object returnsThis(); + + INestedTestBean getDoctor(); + + INestedTestBean getLawyer(); + + IndexedTestBean getNestedIndexedBean(); + + /** + * Increment the age by one. + * @return the previous age + */ + int haveBirthday(); + + void unreliableFileOperation() throws IOException; + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/IndexedTestBean.java b/org.springframework.aspects/src/test/java/org/springframework/beans/IndexedTestBean.java new file mode 100644 index 0000000000..ddb091770e --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/IndexedTestBean.java @@ -0,0 +1,145 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * @author Juergen Hoeller + * @since 11.11.2003 + */ +public class IndexedTestBean { + + private TestBean[] array; + + private Collection collection; + + private List list; + + private Set set; + + private SortedSet sortedSet; + + private Map map; + + private SortedMap sortedMap; + + + public IndexedTestBean() { + this(true); + } + + public IndexedTestBean(boolean populate) { + if (populate) { + populate(); + } + } + + public void populate() { + TestBean tb0 = new TestBean("name0", 0); + TestBean tb1 = new TestBean("name1", 0); + TestBean tb2 = new TestBean("name2", 0); + TestBean tb3 = new TestBean("name3", 0); + TestBean tb4 = new TestBean("name4", 0); + TestBean tb5 = new TestBean("name5", 0); + TestBean tb6 = new TestBean("name6", 0); + TestBean tb7 = new TestBean("name7", 0); + TestBean tbX = new TestBean("nameX", 0); + TestBean tbY = new TestBean("nameY", 0); + this.array = new TestBean[] {tb0, tb1}; + this.list = new ArrayList(); + this.list.add(tb2); + this.list.add(tb3); + this.set = new TreeSet(); + this.set.add(tb6); + this.set.add(tb7); + this.map = new HashMap(); + this.map.put("key1", tb4); + this.map.put("key2", tb5); + this.map.put("key.3", tb5); + List list = new ArrayList(); + list.add(tbX); + list.add(tbY); + this.map.put("key4", list); + } + + + public TestBean[] getArray() { + return array; + } + + public void setArray(TestBean[] array) { + this.array = array; + } + + public Collection getCollection() { + return collection; + } + + public void setCollection(Collection collection) { + this.collection = collection; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public Set getSet() { + return set; + } + + public void setSet(Set set) { + this.set = set; + } + + public SortedSet getSortedSet() { + return sortedSet; + } + + public void setSortedSet(SortedSet sortedSet) { + this.sortedSet = sortedSet; + } + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } + + public SortedMap getSortedMap() { + return sortedMap; + } + + public void setSortedMap(SortedMap sortedMap) { + this.sortedMap = sortedMap; + } + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/NestedTestBean.java b/org.springframework.aspects/src/test/java/org/springframework/beans/NestedTestBean.java new file mode 100644 index 0000000000..a06e15d150 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/NestedTestBean.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +/** + * Simple nested test bean used for testing bean factories, AOP framework etc. + * + * @author Trevor D. Cook + * @since 30.09.2003 + */ +public class NestedTestBean implements INestedTestBean { + + private String company = ""; + + public NestedTestBean() { + } + + public NestedTestBean(String company) { + setCompany(company); + } + + public void setCompany(String company) { + this.company = (company != null ? company : ""); + } + + public String getCompany() { + return company; + } + + public boolean equals(Object obj) { + if (!(obj instanceof NestedTestBean)) { + return false; + } + NestedTestBean ntb = (NestedTestBean) obj; + return this.company.equals(ntb.company); + } + + public int hashCode() { + return this.company.hashCode(); + } + + public String toString() { + return "NestedTestBean: " + this.company; + } + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/TestBean.java b/org.springframework.aspects/src/test/java/org/springframework/beans/TestBean.java new file mode 100644 index 0000000000..7842bbfeac --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/TestBean.java @@ -0,0 +1,437 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.util.ObjectUtils; + +/** + * Simple test bean used for testing bean factories, the AOP framework etc. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 15 April 2001 + */ +public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOther, Comparable { + + private String beanName; + + private String country; + + private BeanFactory beanFactory; + + private boolean postProcessed; + + private String name; + + private String sex; + + private int age; + + private boolean jedi; + + private ITestBean[] spouses; + + private String touchy; + + private String[] stringArray; + + private Integer[] someIntegerArray; + + private Date date = new Date(); + + private Float myFloat = new Float(0.0); + + private Collection friends = new LinkedList(); + + private Set someSet = new HashSet(); + + private Map someMap = new HashMap(); + + private List someList = new ArrayList(); + + private Properties someProperties = new Properties(); + + private INestedTestBean doctor = new NestedTestBean(); + + private INestedTestBean lawyer = new NestedTestBean(); + + private IndexedTestBean nestedIndexedBean; + + private boolean destroyed; + + private Number someNumber; + + private Colour favouriteColour; + + private Boolean someBoolean; + + private List otherColours; + + private List pets; + + + public TestBean() { + } + + public TestBean(String name) { + this.name = name; + } + + public TestBean(ITestBean spouse) { + this.spouses = new ITestBean[] {spouse}; + } + + public TestBean(String name, int age) { + this.name = name; + this.age = age; + } + + public TestBean(ITestBean spouse, Properties someProperties) { + this.spouses = new ITestBean[] {spouse}; + this.someProperties = someProperties; + } + + public TestBean(List someList) { + this.someList = someList; + } + + public TestBean(Set someSet) { + this.someSet = someSet; + } + + public TestBean(Map someMap) { + this.someMap = someMap; + } + + public TestBean(Properties someProperties) { + this.someProperties = someProperties; + } + + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public BeanFactory getBeanFactory() { + return beanFactory; + } + + public void setPostProcessed(boolean postProcessed) { + this.postProcessed = postProcessed; + } + + public boolean isPostProcessed() { + return postProcessed; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + if (this.name == null) { + this.name = sex; + } + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public boolean isJedi() { + return jedi; + } + + public void setJedi(boolean jedi) { + this.jedi = jedi; + } + + public ITestBean getSpouse() { + return (spouses != null ? spouses[0] : null); + } + + public void setSpouse(ITestBean spouse) { + this.spouses = new ITestBean[] {spouse}; + } + + public ITestBean[] getSpouses() { + return spouses; + } + + public String getTouchy() { + return touchy; + } + + public void setTouchy(String touchy) throws Exception { + if (touchy.indexOf('.') != -1) { + throw new Exception("Can't contain a ."); + } + if (touchy.indexOf(',') != -1) { + throw new NumberFormatException("Number format exception: contains a ,"); + } + this.touchy = touchy; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String[] getStringArray() { + return stringArray; + } + + public void setStringArray(String[] stringArray) { + this.stringArray = stringArray; + } + + public Integer[] getSomeIntegerArray() { + return someIntegerArray; + } + + public void setSomeIntegerArray(Integer[] someIntegerArray) { + this.someIntegerArray = someIntegerArray; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Float getMyFloat() { + return myFloat; + } + + public void setMyFloat(Float myFloat) { + this.myFloat = myFloat; + } + + public Collection getFriends() { + return friends; + } + + public void setFriends(Collection friends) { + this.friends = friends; + } + + public Set getSomeSet() { + return someSet; + } + + public void setSomeSet(Set someSet) { + this.someSet = someSet; + } + + public Map getSomeMap() { + return someMap; + } + + public void setSomeMap(Map someMap) { + this.someMap = someMap; + } + + public List getSomeList() { + return someList; + } + + public void setSomeList(List someList) { + this.someList = someList; + } + + public Properties getSomeProperties() { + return someProperties; + } + + public void setSomeProperties(Properties someProperties) { + this.someProperties = someProperties; + } + + public INestedTestBean getDoctor() { + return doctor; + } + + public void setDoctor(INestedTestBean doctor) { + this.doctor = doctor; + } + + public INestedTestBean getLawyer() { + return lawyer; + } + + public void setLawyer(INestedTestBean lawyer) { + this.lawyer = lawyer; + } + + public Number getSomeNumber() { + return someNumber; + } + + public void setSomeNumber(Number someNumber) { + this.someNumber = someNumber; + } + + public Colour getFavouriteColour() { + return favouriteColour; + } + + public void setFavouriteColour(Colour favouriteColour) { + this.favouriteColour = favouriteColour; + } + + public Boolean getSomeBoolean() { + return someBoolean; + } + + public void setSomeBoolean(Boolean someBoolean) { + this.someBoolean = someBoolean; + } + + public IndexedTestBean getNestedIndexedBean() { + return nestedIndexedBean; + } + + public void setNestedIndexedBean(IndexedTestBean nestedIndexedBean) { + this.nestedIndexedBean = nestedIndexedBean; + } + + public List getOtherColours() { + return otherColours; + } + + public void setOtherColours(List otherColours) { + this.otherColours = otherColours; + } + + public List getPets() { + return pets; + } + + public void setPets(List pets) { + this.pets = pets; + } + + + /** + * @see org.springframework.beans.ITestBean#exceptional(Throwable) + */ + public void exceptional(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + } + + public void unreliableFileOperation() throws IOException { + throw new IOException(); + } + /** + * @see org.springframework.beans.ITestBean#returnsThis() + */ + public Object returnsThis() { + return this; + } + + /** + * @see org.springframework.beans.IOther#absquatulate() + */ + public void absquatulate() { + } + + public int haveBirthday() { + return age++; + } + + + public void destroy() { + this.destroyed = true; + } + + public boolean wasDestroyed() { + return destroyed; + } + + + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || !(other instanceof TestBean)) { + return false; + } + TestBean tb2 = (TestBean) other; + return (ObjectUtils.nullSafeEquals(this.name, tb2.name) && this.age == tb2.age); + } + + public int hashCode() { + return this.age; + } + + public int compareTo(Object other) { + if (this.name != null && other instanceof TestBean) { + return this.name.compareTo(((TestBean) other).getName()); + } + else { + return 1; + } + } + + public String toString() { + return this.name; + } + +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/BeanConfigurerTests.java b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/BeanConfigurerTests.java new file mode 100644 index 0000000000..59c2bc88f6 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/BeanConfigurerTests.java @@ -0,0 +1,622 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.aspectj; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; + +import junit.framework.TestCase; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.annotation.Autowire; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.mail.MailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +/** + * @author Adrian Colyer + * @author Rod Johnson + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class BeanConfigurerTests extends TestCase { + + private ClassPathXmlApplicationContext context; + + @Override + protected void setUp() throws Exception { + this.context = + new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/beanConfigurerTests.xml"); + } + + public void testConfigurableWithExplicitBeanName() { + ShouldBeConfiguredBySpring myObject = new ShouldBeConfiguredBySpring(); + assertEquals("Rod", myObject.getName()); + } + + public void testInjectionAfterRefresh() { + context.refresh(); + ShouldBeConfiguredBySpring myObject = new ShouldBeConfiguredBySpring(); + assertEquals("Rod", myObject.getName()); + } + + public void testWithoutAnnotation() { + ShouldNotBeConfiguredBySpring myObject = new ShouldNotBeConfiguredBySpring(); + assertNull("Name should not have been set", myObject.getName()); + } + + public void testConfigurableWithImplicitBeanName() { + ShouldBeConfiguredBySpringUsingTypeNameAsBeanName myObject = + new ShouldBeConfiguredBySpringUsingTypeNameAsBeanName(); + assertEquals("Rob", myObject.getName()); + } + + public void testConfigurableUsingAutowireByType() { + ShouldBeConfiguredBySpringUsingAutowireByType myObject = + new ShouldBeConfiguredBySpringUsingAutowireByType(); + assertNotNull(myObject.getFriend()); + assertEquals("Ramnivas", myObject.getFriend().getName()); + } + + public void testConfigurableUsingAutowireByName() { + ValidAutowireByName myObject = new ValidAutowireByName(); + assertNotNull(myObject.getRamnivas()); + assertEquals("Ramnivas", myObject.getRamnivas().getName()); + } + + public void testInvalidAutowireByName() { + try { + new InvalidAutowireByName(); + fail("Autowire by name cannot work"); + } + catch (UnsatisfiedDependencyException ex) { + // Ok + } + } + + public void testNewAspectAppliesToArbitraryNonAnnotatedPojo() { + ArbitraryExistingPojo aep = new ArbitraryExistingPojo(); + assertNotNull(aep.friend); + assertEquals("Ramnivas", aep.friend.getName()); + } + + public void testNewAspectThatWasNotAddedToSpringContainer() { + try{ + new ClassThatWillNotActuallyBeWired(); + } + catch (IllegalStateException ex) { + assertTrue(ex.getMessage().indexOf("BeanFactory") != -1); + } + } + + public void testInjectionOnDeserialization() throws Exception { + ShouldBeConfiguredBySpring domainObject = new ShouldBeConfiguredBySpring(); + domainObject.setName("Anonymous"); + ShouldBeConfiguredBySpring deserializedDomainObject = + serializeAndDeserialize(domainObject); + assertEquals("Dependency injected on deserialization","Rod",deserializedDomainObject.getName()); + } + + public void testInjectionOnDeserializationForClassesThatContainsPublicReadResolve() throws Exception { + ShouldBeConfiguredBySpringContainsPublicReadResolve domainObject = new ShouldBeConfiguredBySpringContainsPublicReadResolve(); + domainObject.setName("Anonymous"); + ShouldBeConfiguredBySpringContainsPublicReadResolve deserializedDomainObject = + serializeAndDeserialize(domainObject); + assertEquals("Dependency injected on deserialization","Rod",deserializedDomainObject.getName()); + assertEquals("User readResolve should take precedence", 1, deserializedDomainObject.readResolveInvocationCount); + } + + // See ShouldBeConfiguredBySpringContainsPrivateReadResolve +// public void testInjectionOnDeserializationForClassesThatContainsPrivateReadResolve() throws Exception { +// ShouldBeConfiguredBySpringContainsPrivateReadResolve domainObject = new ShouldBeConfiguredBySpringContainsPrivateReadResolve(); +// domainObject.setName("Anonymous"); +// ShouldBeConfiguredBySpringContainsPrivateReadResolve deserializedDomainObject = +// serializeAndDeserialize(domainObject); +// assertEquals("Dependency injected on deserialization","Rod",deserializedDomainObject.getName()); +// } + + public void testNonInjectionOnDeserializationForSerializedButNotConfigured() throws Exception { + SerializableThatShouldNotBeConfiguredBySpring domainObject = new SerializableThatShouldNotBeConfiguredBySpring(); + domainObject.setName("Anonymous"); + SerializableThatShouldNotBeConfiguredBySpring deserializedDomainObject = + serializeAndDeserialize(domainObject); + assertEquals("Dependency injected on deserialization","Anonymous",deserializedDomainObject.getName()); + } + + public void testSubBeanConfiguredOnlyOnce() throws Exception { + SubBean subBean = new SubBean(); + assertEquals("Property injected more than once", 1, subBean.setterCount); + } + + public void testSubBeanConfiguredOnlyOnceForPreConstruction() throws Exception { + SubBeanPreConstruction subBean = new SubBeanPreConstruction(); + assertEquals("Property injected more than once", 1, subBean.setterCount); + } + + public void testSubSerializableBeanConfiguredOnlyOnce() throws Exception { + SubSerializableBean subBean = new SubSerializableBean(); + assertEquals("Property injected more than once", 1, subBean.setterCount); + subBean.setterCount = 0; + + SubSerializableBean deserializedSubBean = serializeAndDeserialize(subBean); + assertEquals("Property injected more than once", 1, deserializedSubBean.setterCount); + } + + public void testPreConstructionConfiguredBean() { + PreConstructionConfiguredBean bean = new PreConstructionConfiguredBean(); + assertTrue("Injection didn't occur before construction", bean.preConstructionConfigured); + } + + public void testPreConstructionConfiguredBeanDeserializationReinjection() throws Exception { + PreConstructionConfiguredBean bean = new PreConstructionConfiguredBean(); + PreConstructionConfiguredBean deserialized = serializeAndDeserialize(bean); + assertEquals("Injection didn't occur upon deserialization", "ramnivas", deserialized.getName()); + } + + public void testPostConstructionConfiguredBean() { + PostConstructionConfiguredBean bean = new PostConstructionConfiguredBean(); + assertFalse("Injection occurred before construction", bean.preConstructionConfigured); + } + + public void testPostConstructionConfiguredBeanDeserializationReinjection() throws Exception { + PostConstructionConfiguredBean bean = new PostConstructionConfiguredBean(); + PostConstructionConfiguredBean deserialized = serializeAndDeserialize(bean); + assertEquals("Injection didn't occur upon deserialization", "ramnivas", deserialized.getName()); + } + + public void testInterfaceDrivenDependencyInjection() { + MailClientDependencyInjectionAspect.aspectOf().setMailSender(new JavaMailSenderImpl()); + Order testOrder = new Order(); + assertNotNull("Interface driven injection didn't occur for direct construction", testOrder.mailSender); + } + + public void testInterfaceDrivenDependencyInjectionMultipleInterfaces() { + MailClientDependencyInjectionAspect.aspectOf().setMailSender(new JavaMailSenderImpl()); + PaymentProcessorDependencyInjectionAspect.aspectOf().setPaymentProcessor(new PaymentProcessor()); + + ShoppingCart testCart = new ShoppingCart(); + + assertNotNull("Interface driven injection didn't occur for direct construction", testCart.mailSender); + assertNotNull("Interface driven injection didn't occur for direct construction", testCart.paymentProcessor); + } + + public void testInterfaceDrivenDependencyInjectionUponDeserialization() throws Exception { + MailClientDependencyInjectionAspect.aspectOf().setMailSender(new JavaMailSenderImpl()); + Order testOrder = new Order(); + Order deserializedOrder = serializeAndDeserialize(testOrder); + assertNotNull("Interface driven injection didn't occur for deserialization", testOrder.mailSender); + } + + public void testFieldAutoWiredAnnotationInjection() { + FieldAutoWiredServiceBean bean = new FieldAutoWiredServiceBean(); + assertNotNull(bean.testService); + } + + public void testMethodAutoWiredAnnotationInjection() { + MethodAutoWiredServiceBean bean = new MethodAutoWiredServiceBean(); + assertNotNull(bean.testService); + } + + public void testMultiArgumentMethodAutoWiredAnnotationInjection() { + MultiArgumentMethodAutoWiredServiceBean bean = new MultiArgumentMethodAutoWiredServiceBean(); + assertNotNull(bean.testService); + assertNotNull(bean.paymentService); + } + + public void testGenericParameterConfigurableBean() { + GenericParameterConfigurableBean bean = new GenericParameterConfigurableBean(); + assertNotNull(bean.testService); + } + + @SuppressWarnings("unchecked") + private T serializeAndDeserialize(T serializable) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(serializable); + oos.close(); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + return (T)ois.readObject(); + } + + + @Configurable("beanOne") + private static class ShouldBeConfiguredBySpring implements Serializable { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + @Configurable("beanOne") + private static class ShouldBeConfiguredBySpringContainsPublicReadResolve implements Serializable { + + private String name; + + private int readResolveInvocationCount = 0; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public Object readResolve() throws ObjectStreamException { + readResolveInvocationCount++; + return this; + } + } + + +// Won't work until we use hasmethod() experimental pointcut in AspectJ. +// @Configurable("beanOne") +// private static class ShouldBeConfiguredBySpringContainsPrivateReadResolve implements Serializable { +// +// private String name; +// +// public void setName(String name) { +// this.name = name; +// } +// +// public String getName() { +// return this.name; +// } +// +// private Object readResolve() throws ObjectStreamException { +// return this; +// } +// } + + + private static class ShouldNotBeConfiguredBySpring { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + private static class SerializableThatShouldNotBeConfiguredBySpring implements Serializable { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + @Configurable + private static class ShouldBeConfiguredBySpringUsingTypeNameAsBeanName { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + @Configurable(autowire=Autowire.BY_TYPE) + private static class ShouldBeConfiguredBySpringUsingAutowireByType { + + private TestBean friend = null; + + public TestBean getFriend() { + return friend; + } + + public void setFriend(TestBean friend) { + this.friend = friend; + } + } + + + @Configurable(autowire=Autowire.BY_NAME) + private static class ValidAutowireByName { + + private TestBean friend = null; + + public TestBean getRamnivas() { + return friend; + } + + public void setRamnivas(TestBean friend) { + this.friend = friend; + } + } + + + @Configurable(autowire=Autowire.BY_NAME, dependencyCheck=true) + private static class InvalidAutowireByName { + + private TestBean friend; + + public TestBean getFriend() { + return friend; + } + + public void setFriend(TestBean friend) { + this.friend = friend; + } + } + + + private static class ArbitraryExistingPojo { + + private TestBean friend; + + public void setFriend(TestBean f) { + this.friend = f; + } + } + + + public static class CircularFactoryBean implements FactoryBean{ + + public CircularFactoryBean() { +// ValidAutowireByName autowired = new ValidAutowireByName(); +// assertNull(autowired.getRamnivas()); + } + + public Object getObject() throws Exception { + return new TestBean(); + } + + public Class getObjectType() { + return TestBean.class; + } + + public boolean isSingleton() { + return false; + } + } + + + @Configurable + private static class BaseBean { + + public int setterCount; + + private String name; + + public void setName(String name) { + this.name = name; + setterCount++; + } + } + + + private static class SubBean extends BaseBean { + } + + @Configurable(preConstruction=true) + private static class SubBeanPreConstruction extends BaseBean { + } + + @Configurable + private static class BaseSerializableBean implements Serializable { + + public int setterCount; + + private String name; + + public void setName(String name) { + this.name = name; + setterCount++; + } + } + + + private static class SubSerializableBean extends BaseSerializableBean { + } + + + @Aspect + private static class WireArbitraryExistingPojo extends AbstractBeanConfigurerAspect { + + @Pointcut("initialization(ArbitraryExistingPojo.new(..)) && this(beanInstance)") + protected void beanCreation(Object beanInstance){ + + } + } + + + @Aspect + private static class AspectThatWillNotBeUsed extends AbstractBeanConfigurerAspect { + + @Pointcut("initialization(ClassThatWillNotActuallyBeWired.new(..)) && this(beanInstance)") + protected void beanCreation(Object beanInstance){ + } + } + + private static aspect MailClientDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect { + private MailSender mailSender; + + public pointcut inConfigurableBean() : within(MailSenderClient+); + + public void configureBean(Object bean) { + ((MailSenderClient)bean).setMailSender(this.mailSender); + } + + declare parents: MailSenderClient implements ConfigurableObject; + + public void setMailSender(MailSender mailSender) { + this.mailSender = mailSender; + } + } + + private static aspect PaymentProcessorDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect { + private PaymentProcessor paymentProcessor; + + public pointcut inConfigurableBean() : within(PaymentProcessorClient+); + + public void configureBean(Object bean) { + ((PaymentProcessorClient)bean).setPaymentProcessor(this.paymentProcessor); + } + + declare parents: PaymentProcessorClient implements ConfigurableObject; + + public void setPaymentProcessor(PaymentProcessor paymentProcessor) { + this.paymentProcessor = paymentProcessor; + } + } + + public static interface MailSenderClient { + public void setMailSender(MailSender mailSender); + } + + public static interface PaymentProcessorClient { + public void setPaymentProcessor(PaymentProcessor paymentProcessor); + } + + public static class PaymentProcessor { + + } + + public static class Order implements MailSenderClient, Serializable { + private transient MailSender mailSender; + + public void setMailSender(MailSender mailSender) { + this.mailSender = mailSender; + } + } + + public static class ShoppingCart implements MailSenderClient, PaymentProcessorClient { + private transient MailSender mailSender; + private transient PaymentProcessor paymentProcessor; + + public void setMailSender(MailSender mailSender) { + this.mailSender = mailSender; + } + + public void setPaymentProcessor(PaymentProcessor paymentProcessor) { + this.paymentProcessor = paymentProcessor; + } + } + + private static class ClassThatWillNotActuallyBeWired { + + } + + @Configurable + private static class PreOrPostConstructionConfiguredBean implements Serializable { + private transient String name; + protected transient boolean preConstructionConfigured; + transient int count; + + public PreOrPostConstructionConfiguredBean() { + preConstructionConfigured = (this.name != null); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + } + + + @Configurable(preConstruction=true) + public static class PreConstructionConfiguredBean extends PreOrPostConstructionConfiguredBean { + } + + + @Configurable(preConstruction=false) + private static class PostConstructionConfiguredBean extends PreOrPostConstructionConfiguredBean { + } + + @Configurable + public static class FieldAutoWiredServiceBean { + @Autowired transient private TestService testService; + } + + @Configurable + public static class MethodAutoWiredServiceBean { + transient private TestService testService; + + @Autowired + public void setTestService(TestService testService) { + this.testService = testService; + } + } + + @Configurable + public static class MultiArgumentMethodAutoWiredServiceBean { + transient private TestService testService; + transient private PaymentService paymentService; + + @Autowired + public void setDependencies(TestService testService, PaymentService paymentService) { + this.testService = testService; + this.paymentService = paymentService; + } + } + + @Configurable + public static class GenericParameterConfigurableBean { + private TestService testService; + + public void setTestService(TestService testService) { + this.testService = testService; + } + } + + public static class TestService { + + } + + public static class PaymentService { + + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java new file mode 100644 index 0000000000..aa8aef07a1 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.aspectj; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import junit.framework.TestCase; + +public class SpringConfiguredWithAutoProxyingTests extends TestCase { + + @Override + protected void setUp() throws Exception { + new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml"); + } + + public void testSpringConfiguredAndAutoProxyUsedTogether() { + ; // set up is sufficient to trigger failure if this is going to fail... + } +} \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/beanConfigurerTests.xml b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/beanConfigurerTests.xml new file mode 100644 index 0000000000..8dc971af52 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/beanConfigurerTests.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/springConfigured.xml b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/springConfigured.xml new file mode 100644 index 0000000000..1ee36a11da --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/springConfigured.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java new file mode 100644 index 0000000000..d5c2531fbd --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/CallCountingTransactionManager.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction; + +import org.springframework.transaction.support.AbstractPlatformTransactionManager; +import org.springframework.transaction.support.DefaultTransactionStatus; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class CallCountingTransactionManager extends AbstractPlatformTransactionManager { + + public TransactionDefinition lastDefinition; + public int begun; + public int commits; + public int rollbacks; + public int inflight; + + protected Object doGetTransaction() { + return new Object(); + } + + protected void doBegin(Object transaction, TransactionDefinition definition) { + this.lastDefinition = definition; + ++begun; + ++inflight; + } + + protected void doCommit(DefaultTransactionStatus status) { + ++commits; + --inflight; + } + + protected void doRollback(DefaultTransactionStatus status) { + ++rollbacks; + --inflight; + } + + public void clear() { + begun = commits = rollbacks = inflight = 0; + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java new file mode 100644 index 0000000000..899e0feb67 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 11 Sep 2006 by Adrian Colyer + */ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class ClassWithPrivateAnnotatedMember { + + public void doSomething() { + doInTransaction(); + } + + @Transactional + private void doInTransaction() {} +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java new file mode 100644 index 0000000000..a4cb30c50f --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 11 Sep 2006 by Adrian Colyer + */ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class ClassWithProtectedAnnotatedMember { + + public void doSomething() { + doInTransaction(); + } + + @Transactional + protected void doInTransaction() {} +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java new file mode 100644 index 0000000000..48670fbf6a --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java @@ -0,0 +1,10 @@ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public interface ITransactional { + + Object echo(Throwable t) throws Throwable; + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java new file mode 100644 index 0000000000..29b9b311b7 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java @@ -0,0 +1,19 @@ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +public class MethodAnnotationOnClassWithNoInterface { + + @Transactional(rollbackFor=InterruptedException.class) + public Object echo(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + return t; + } + + public void noTransactionAttribute() { + + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests-context.xml b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests-context.xml new file mode 100644 index 0000000000..02ea3f7799 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests-context.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java new file mode 100644 index 0000000000..39fedc70b3 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java @@ -0,0 +1,261 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.aspectj; + +import java.lang.reflect.Method; + +import junit.framework.AssertionFailedError; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; +import org.springframework.transaction.CallCountingTransactionManager; +import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; +import org.springframework.transaction.interceptor.TransactionAspectSupport; +import org.springframework.transaction.interceptor.TransactionAttribute; + +/** + * @author Rod Johnson + * @author Ramnivas Laddad + */ +public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests { + + private TransactionAspectSupport transactionAspect; + + private CallCountingTransactionManager txManager; + + private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface; + + private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod; + + private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod; + + private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface(); + + + public void setAnnotationOnlyOnClassWithNoInterface( + TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) { + this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface; + } + + public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) { + this.beanWithAnnotatedProtectedMethod = aBean; + } + + public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) { + this.beanWithAnnotatedPrivateMethod = aBean; + } + + public void setTransactionAspect(TransactionAspectSupport transactionAspect) { + this.transactionAspect = transactionAspect; + this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager(); + } + + public TransactionAspectSupport getTransactionAspect() { + return this.transactionAspect; + } + + @Override + protected String getConfigPath() { + return "TransactionAspectTests-context.xml"; + } + + + public void testCommitOnAnnotatedClass() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + annotationOnlyOnClassWithNoInterface.echo(null); + assertEquals(1, txManager.commits); + } + + public void testCommitOnAnnotatedProtectedMethod() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + beanWithAnnotatedProtectedMethod.doInTransaction(); + assertEquals(1, txManager.commits); + } + + public void testCommitOnAnnotatedPrivateMethod() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + beanWithAnnotatedPrivateMethod.doSomething(); + assertEquals(1, txManager.commits); + } + + public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable { + txManager.clear(); + assertEquals(0,txManager.begun); + annotationOnlyOnClassWithNoInterface.nonTransactionalMethod(); + assertEquals(0,txManager.begun); + } + + public void testCommitOnAnnotatedMethod() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + methodAnnotationOnly.echo(null); + assertEquals(1, txManager.commits); + } + + + public static class NotTransactional { + public void noop() { + } + } + + public void testNotTransactional() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + new NotTransactional().noop(); + assertEquals(0, txManager.begun); + } + + + public void testDefaultCommitOnAnnotatedClass() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return annotationOnlyOnClassWithNoInterface.echo(new Exception()); + } + }, false); + } + + public void testDefaultRollbackOnAnnotatedClass() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException()); + } + }, true); + } + + + public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface { + } + + public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception()); + } + }, false); + } + + public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface { + } + + public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception()); + } + }, false); + } + + public static class ImplementsAnnotatedInterface implements ITransactional { + public Object echo(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + return t; + } + } + + public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable { +// testRollback(new TransactionOperationCallback() { +// public Object performTransactionalOperation() throws Throwable { +// return new ImplementsAnnotatedInterface().echo(new Exception()); +// } +// }, false); + + final Exception ex = new Exception(); + testNotTransactional(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new ImplementsAnnotatedInterface().echo(ex); + } + }, ex); + } + + /** + * Note: resolution does not occur. Thus we can't make a class transactional if + * it implements a transactionally annotated interface. This behaviour could only + * be changed in AbstractFallbackTransactionAttributeSource in Spring proper. + * @throws SecurityException + * @throws NoSuchMethodException + */ + public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException { + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class); + TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class); + assertNull(ta); + } + + + public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable { +// testRollback(new TransactionOperationCallback() { +// public Object performTransactionalOperation() throws Throwable { +// return new ImplementsAnnotatedInterface().echo(new RuntimeException()); +// } +// }, true); + + final Exception rollbackProvokingException = new RuntimeException(); + testNotTransactional(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new ImplementsAnnotatedInterface().echo(rollbackProvokingException); + } + }, rollbackProvokingException); + } + + + protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + try { + toc.performTransactionalOperation(); + assertEquals(1, txManager.commits); + } + catch (Throwable caught) { + if (caught instanceof AssertionFailedError) { + return; + } + } + + if (rollback) { + assertEquals(1, txManager.rollbacks); + } + assertEquals(1, txManager.begun); + } + + protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + try { + toc.performTransactionalOperation(); + } + catch (Throwable t) { + if (expected == null) { + fail("Expected " + expected); + } + assertSame(expected, t); + } + finally { + assertEquals(0, txManager.begun); + } + } + + + private interface TransactionOperationCallback { + + Object performTransactionalOperation() throws Throwable; + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java new file mode 100644 index 0000000000..a111f57241 --- /dev/null +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java @@ -0,0 +1,20 @@ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public class TransactionalAnnotationOnlyOnClassWithNoInterface { + + public Object echo(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + return t; + } + + void nonTransactionalMethod() { + // no-op + } + +} +