/* * Copyright 2012-2017 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.glowroot.agent.weaving; import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; import com.google.common.base.StandardSystemProperty; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.glowroot.agent.config.ConfigService; import org.glowroot.agent.impl.ThreadContextImpl; import org.glowroot.agent.impl.TimerNameCache; import org.glowroot.agent.impl.TransactionRegistry; import org.glowroot.agent.plugin.api.util.FastThreadLocal; import org.glowroot.agent.plugin.api.weaving.Mixin; import org.glowroot.agent.plugin.api.weaving.OptionalReturn; import org.glowroot.agent.plugin.api.weaving.Pointcut; import org.glowroot.agent.plugin.api.weaving.Shim; import org.glowroot.agent.weaving.ClassLoaders.LazyDefinedClass; import org.glowroot.agent.weaving.SomeAspect.AnotherAnnotationBasedAdvice; import org.glowroot.agent.weaving.SomeAspect.AnotherAnnotationBasedAdviceButWrong; import org.glowroot.agent.weaving.SomeAspect.BasicAdvice; import org.glowroot.agent.weaving.SomeAspect.BasicAnnotationBasedAdvice; import org.glowroot.agent.weaving.SomeAspect.BasicHighOrderAdvice; import org.glowroot.agent.weaving.SomeAspect.BasicMiscAllConstructorAdvice; import org.glowroot.agent.weaving.SomeAspect.BasicMiscConstructorAdvice; import org.glowroot.agent.weaving.SomeAspect.BasicWithInnerClassAdvice; import org.glowroot.agent.weaving.SomeAspect.BasicWithInnerClassArgAdvice; import org.glowroot.agent.weaving.SomeAspect.BindAutoboxedReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.BindClassMetaAdvice; import org.glowroot.agent.weaving.SomeAspect.BindMethodMetaAdvice; import org.glowroot.agent.weaving.SomeAspect.BindMethodMetaArrayAdvice; import org.glowroot.agent.weaving.SomeAspect.BindMethodMetaReturnArrayAdvice; import org.glowroot.agent.weaving.SomeAspect.BindMethodNameAdvice; import org.glowroot.agent.weaving.SomeAspect.BindOptionalPrimitiveReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.BindOptionalReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.BindOptionalVoidReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.BindParameterAdvice; import org.glowroot.agent.weaving.SomeAspect.BindParameterArrayAdvice; import org.glowroot.agent.weaving.SomeAspect.BindPrimitiveBooleanTravelerAdvice; import org.glowroot.agent.weaving.SomeAspect.BindPrimitiveReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.BindPrimitiveTravelerAdvice; import org.glowroot.agent.weaving.SomeAspect.BindReceiverAdvice; import org.glowroot.agent.weaving.SomeAspect.BindReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.BindThrowableAdvice; import org.glowroot.agent.weaving.SomeAspect.BindTravelerAdvice; import org.glowroot.agent.weaving.SomeAspect.BrokenAdvice; import org.glowroot.agent.weaving.SomeAspect.ChangeReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.CircularClassDependencyAdvice; import org.glowroot.agent.weaving.SomeAspect.ClassNamePatternAdvice; import org.glowroot.agent.weaving.SomeAspect.ComplexSuperTypeRestrictionAdvice; import org.glowroot.agent.weaving.SomeAspect.FinalMethodAdvice; import org.glowroot.agent.weaving.SomeAspect.GenericMiscAdvice; import org.glowroot.agent.weaving.SomeAspect.HasString; import org.glowroot.agent.weaving.SomeAspect.HasStringClassMixin; import org.glowroot.agent.weaving.SomeAspect.HasStringInterfaceMixin; import org.glowroot.agent.weaving.SomeAspect.HasStringMultipleMixin; import org.glowroot.agent.weaving.SomeAspect.InterfaceAppearsTwiceInHierarchyAdvice; import org.glowroot.agent.weaving.SomeAspect.MatchingPublicNonStaticAdvice; import org.glowroot.agent.weaving.SomeAspect.MethodParametersBadDotDotAdvice1; import org.glowroot.agent.weaving.SomeAspect.MethodParametersDotDotAdvice1; import org.glowroot.agent.weaving.SomeAspect.MethodParametersDotDotAdvice2; import org.glowroot.agent.weaving.SomeAspect.MethodParametersDotDotAdvice3; import org.glowroot.agent.weaving.SomeAspect.MethodReturnCharSequenceAdvice; import org.glowroot.agent.weaving.SomeAspect.MethodReturnStringAdvice; import org.glowroot.agent.weaving.SomeAspect.MethodReturnVoidAdvice; import org.glowroot.agent.weaving.SomeAspect.MoreNotPerfectBytecodeAdvice; import org.glowroot.agent.weaving.SomeAspect.MultipleMethodsAdvice; import org.glowroot.agent.weaving.SomeAspect.NonMatchingMethodReturnAdvice; import org.glowroot.agent.weaving.SomeAspect.NonMatchingMethodReturnAdvice2; import org.glowroot.agent.weaving.SomeAspect.NonMatchingStaticAdvice; import org.glowroot.agent.weaving.SomeAspect.NotPerfectBytecodeAdvice; import org.glowroot.agent.weaving.SomeAspect.PrimitiveAdvice; import org.glowroot.agent.weaving.SomeAspect.PrimitiveWithAutoboxAdvice; import org.glowroot.agent.weaving.SomeAspect.PrimitiveWithWildcardAdvice; import org.glowroot.agent.weaving.SomeAspect.Shimmy; import org.glowroot.agent.weaving.SomeAspect.StaticAdvice; import org.glowroot.agent.weaving.SomeAspect.SubTypeRestrictionAdvice; import org.glowroot.agent.weaving.SomeAspect.SubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice; import org.glowroot.agent.weaving.SomeAspect.SubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice; import org.glowroot.agent.weaving.SomeAspect.SuperBasicAdvice; import org.glowroot.agent.weaving.SomeAspect.SuperTypeRestrictionAdvice; import org.glowroot.agent.weaving.SomeAspect.SuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice; import org.glowroot.agent.weaving.SomeAspect.TestBytecodeWithStackFramesAdvice; import org.glowroot.agent.weaving.SomeAspect.TestBytecodeWithStackFramesAdvice2; import org.glowroot.agent.weaving.SomeAspect.TestBytecodeWithStackFramesAdvice3; import org.glowroot.agent.weaving.SomeAspect.TestBytecodeWithStackFramesAdvice4; import org.glowroot.agent.weaving.SomeAspect.TestBytecodeWithStackFramesAdvice5; import org.glowroot.agent.weaving.SomeAspect.TestBytecodeWithStackFramesAdvice6; import org.glowroot.agent.weaving.SomeAspect.TestClassMeta; import org.glowroot.agent.weaving.SomeAspect.TestMethodMeta; import org.glowroot.agent.weaving.SomeAspect.TestTroublesomeBytecodeAdvice; import org.glowroot.agent.weaving.SomeAspect.ThrowInOnBeforeAdvice; import org.glowroot.agent.weaving.SomeAspect.ThrowableToStringAdvice; import org.glowroot.agent.weaving.SomeAspect.WildMethodAdvice; import org.glowroot.agent.weaving.SomeAspectThreadLocals.IntegerThreadLocal; import org.glowroot.agent.weaving.other.ArrayMisc; import org.glowroot.agent.weaving.targets.AbstractMisc.ExtendsAbstractMisc; import org.glowroot.agent.weaving.targets.AbstractNotMisc.ExtendsAbstractNotMisc; import org.glowroot.agent.weaving.targets.AbstractNotMiscWithFinal.ExtendsAbstractNotMiscWithFinal; import org.glowroot.agent.weaving.targets.AccessibilityMisc; import org.glowroot.agent.weaving.targets.BasicMisc; import org.glowroot.agent.weaving.targets.BytecodeWithStackFramesMisc; import org.glowroot.agent.weaving.targets.DuplicateStackFramesMisc; import org.glowroot.agent.weaving.targets.ExtendsPackagePrivateMisc; import org.glowroot.agent.weaving.targets.GenericAbstractMiscImpl; import org.glowroot.agent.weaving.targets.GenericMisc; import org.glowroot.agent.weaving.targets.GenericMiscImpl; import org.glowroot.agent.weaving.targets.InnerTryCatchMisc; import org.glowroot.agent.weaving.targets.Misc; import org.glowroot.agent.weaving.targets.Misc2; import org.glowroot.agent.weaving.targets.NativeMisc; import org.glowroot.agent.weaving.targets.NestingMisc; import org.glowroot.agent.weaving.targets.OnlyThrowingMisc; import org.glowroot.agent.weaving.targets.PrimitiveMisc; import org.glowroot.agent.weaving.targets.ShimmedMisc; import org.glowroot.agent.weaving.targets.StaticMisc; import org.glowroot.agent.weaving.targets.SubBasicMisc; import org.glowroot.agent.weaving.targets.SubException; import org.glowroot.agent.weaving.targets.SubMisc; import org.glowroot.agent.weaving.targets.SuperBasic; import org.glowroot.agent.weaving.targets.SuperBasicMisc; import org.glowroot.agent.weaving.targets.ThrowingMisc; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class WeaverTest { @Before public void before() { SomeAspectThreadLocals.resetThreadLocals(); } // ===================== @IsEnabled ===================== @Test public void shouldExecuteEnabledAdvice() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteEnabledAdviceOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BasicAdvice.class); // when try { test.execute1(); } catch (Throwable t) { } // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteEnabledAdviceOnOnlyThrow() throws Exception { // given Misc test = newWovenObject(OnlyThrowingMisc.class, Misc.class, BasicAdvice.class); // when try { test.execute1(); } catch (Throwable t) { } // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldNotExecuteDisabledAdvice() throws Exception { // given BasicAdvice.disable(); Misc test = newWovenObject(BasicMisc.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldNotExecuteDisabledAdviceOnThrow() throws Exception { // given BasicAdvice.disable(); Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BasicAdvice.class); // when try { test.execute1(); } catch (Throwable t) { } // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } // ===================== @BindReceiver ===================== @Test public void shouldBindReceiver() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindReceiverAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.isEnabledReceiver.get()).isEqualTo(test); assertThat(SomeAspectThreadLocals.onBeforeReceiver.get()).isEqualTo(test); assertThat(SomeAspectThreadLocals.onReturnReceiver.get()).isEqualTo(test); assertThat(SomeAspectThreadLocals.onThrowReceiver.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterReceiver.get()).isEqualTo(test); } @Test public void shouldBindReceiverOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindReceiverAdvice.class); // when try { test.execute1(); } catch (Throwable t) { } // then assertThat(SomeAspectThreadLocals.isEnabledReceiver.get()).isEqualTo(test); assertThat(SomeAspectThreadLocals.onBeforeReceiver.get()).isEqualTo(test); assertThat(SomeAspectThreadLocals.onReturnReceiver.get()).isNull(); assertThat(SomeAspectThreadLocals.onThrowReceiver.get()).isEqualTo(test); assertThat(SomeAspectThreadLocals.onAfterReceiver.get()).isEqualTo(test); } // ===================== @BindParameter ===================== @Test public void shouldBindParameters() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindParameterAdvice.class); // when test.executeWithArgs("one", 2); // then Object[] parameters = new Object[] {"one", 2}; assertThat(SomeAspectThreadLocals.isEnabledParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onBeforeParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onReturnParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onThrowParams.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterParams.get()).isEqualTo(parameters); } @Test public void shouldBindParameterOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindParameterAdvice.class); // when try { test.executeWithArgs("one", 2); } catch (Throwable t) { } // then Object[] parameters = new Object[] {"one", 2}; assertThat(SomeAspectThreadLocals.isEnabledParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onBeforeParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onReturnParams.get()).isNull(); assertThat(SomeAspectThreadLocals.onThrowParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onAfterParams.get()).isEqualTo(parameters); } // ===================== @BindParameterArray ===================== @Test public void shouldBindParameterArray() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindParameterArrayAdvice.class); // when test.executeWithArgs("one", 2); // then Object[] parameters = new Object[] {"one", 2}; assertThat(SomeAspectThreadLocals.isEnabledParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onBeforeParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onReturnParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onThrowParams.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterParams.get()).isEqualTo(parameters); } @Test public void shouldBindParameterArrayOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindParameterArrayAdvice.class); // when try { test.executeWithArgs("one", 2); } catch (Throwable t) { } // then Object[] parameters = new Object[] {"one", 2}; assertThat(SomeAspectThreadLocals.isEnabledParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onBeforeParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onReturnParams.get()).isNull(); assertThat(SomeAspectThreadLocals.onThrowParams.get()).isEqualTo(parameters); assertThat(SomeAspectThreadLocals.onAfterParams.get()).isEqualTo(parameters); } // ===================== @BindTraveler ===================== @Test public void shouldBindTraveler() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindTravelerAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onReturnTraveler.get()).isEqualTo("a traveler"); assertThat(SomeAspectThreadLocals.onThrowTraveler.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterTraveler.get()).isEqualTo("a traveler"); } @Test public void shouldBindPrimitiveTraveler() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindPrimitiveTravelerAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onReturnTraveler.get()).isEqualTo(3); assertThat(SomeAspectThreadLocals.onThrowTraveler.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterTraveler.get()).isEqualTo(3); } @Test public void shouldBindPrimitiveBooleanTraveler() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindPrimitiveBooleanTravelerAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onReturnTraveler.get()).isEqualTo(true); assertThat(SomeAspectThreadLocals.onThrowTraveler.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterTraveler.get()).isEqualTo(true); } @Test public void shouldBindTravelerOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindTravelerAdvice.class); // when try { test.execute1(); } catch (Throwable t) { } // then assertThat(SomeAspectThreadLocals.onReturnTraveler.get()).isNull(); assertThat(SomeAspectThreadLocals.onThrowTraveler.get()).isEqualTo("a traveler"); assertThat(SomeAspectThreadLocals.onAfterTraveler.get()).isEqualTo("a traveler"); } // ===================== @BindClassMeta ===================== @Test public void shouldBindClassMeta() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindClassMetaAdvice.class, TestClassMeta.class); // when test.execute1(); // then // can't compare Class objects directly since they are in different class loaders due to // IsolatedWeavingClassLoader assertThat(SomeAspectThreadLocals.isEnabledClassMeta.get().getClazzName()) .isEqualTo(BasicMisc.class.getName()); assertThat(SomeAspectThreadLocals.onBeforeClassMeta.get().getClazzName()) .isEqualTo(BasicMisc.class.getName()); assertThat(SomeAspectThreadLocals.onReturnClassMeta.get().getClazzName()) .isEqualTo(BasicMisc.class.getName()); assertThat(SomeAspectThreadLocals.onThrowClassMeta.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterClassMeta.get().getClazzName()) .isEqualTo(BasicMisc.class.getName()); } @Test public void shouldBindClassMetaOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindClassMetaAdvice.class, TestClassMeta.class); // when try { test.execute1(); } catch (Throwable t) { } // then // can't compare Class objects directly since they are in different class loaders due to // IsolatedWeavingClassLoader assertThat(SomeAspectThreadLocals.isEnabledClassMeta.get().getClazzName()) .isEqualTo(ThrowingMisc.class.getName()); assertThat(SomeAspectThreadLocals.onBeforeClassMeta.get().getClazzName()) .isEqualTo(ThrowingMisc.class.getName()); assertThat(SomeAspectThreadLocals.onReturnClassMeta.get()).isNull(); assertThat(SomeAspectThreadLocals.onThrowClassMeta.get().getClazzName()) .isEqualTo(ThrowingMisc.class.getName()); assertThat(SomeAspectThreadLocals.onAfterClassMeta.get().getClazzName()) .isEqualTo(ThrowingMisc.class.getName()); } // ===================== @BindMethodMeta ===================== @Test public void shouldBindMethodMeta() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindMethodMetaAdvice.class, TestMethodMeta.class); // when test.executeWithArgs("one", 2); // then // can't compare Class objects directly since they are in different class loaders due to // IsolatedWeavingClassLoader assertThat(SomeAspectThreadLocals.isEnabledMethodMeta.get().getDeclaringClassName()) .isEqualTo(BasicMisc.class.getName()); assertThat(SomeAspectThreadLocals.isEnabledMethodMeta.get().getReturnTypeName()) .isEqualTo(void.class.getName()); assertThat(SomeAspectThreadLocals.isEnabledMethodMeta.get().getParameterTypeNames()) .containsExactly(String.class.getName(), int.class.getName()); assertThat(SomeAspectThreadLocals.onBeforeMethodMeta.get()) .isEqualTo(SomeAspectThreadLocals.isEnabledMethodMeta.get()); assertThat(SomeAspectThreadLocals.onReturnMethodMeta.get()) .isEqualTo(SomeAspectThreadLocals.isEnabledMethodMeta.get()); assertThat(SomeAspectThreadLocals.onThrowMethodMeta.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterMethodMeta.get()) .isEqualTo(SomeAspectThreadLocals.isEnabledMethodMeta.get()); } @Test public void shouldBindMethodMetaOnThrow() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindMethodMetaAdvice.class, TestMethodMeta.class); // when try { test.executeWithArgs("one", 2); } catch (Throwable t) { } // then // can't compare Class objects directly since they are in different class loaders due to // IsolatedWeavingClassLoader assertThat(SomeAspectThreadLocals.isEnabledMethodMeta.get().getDeclaringClassName()) .isEqualTo(ThrowingMisc.class.getName()); assertThat(SomeAspectThreadLocals.isEnabledMethodMeta.get().getReturnTypeName()) .isEqualTo(void.class.getName()); assertThat(SomeAspectThreadLocals.isEnabledMethodMeta.get().getParameterTypeNames()) .containsExactly(String.class.getName(), int.class.getName()); assertThat(SomeAspectThreadLocals.onBeforeMethodMeta.get()) .isEqualTo(SomeAspectThreadLocals.isEnabledMethodMeta.get()); assertThat(SomeAspectThreadLocals.onReturnMethodMeta.get()).isNull(); assertThat(SomeAspectThreadLocals.onThrowMethodMeta.get()) .isEqualTo(SomeAspectThreadLocals.isEnabledMethodMeta.get()); assertThat(SomeAspectThreadLocals.onAfterMethodMeta.get()) .isEqualTo(SomeAspectThreadLocals.isEnabledMethodMeta.get()); } @Test public void shouldBindMethodMetaArrays() throws Exception { // given Misc test = newWovenObject(ArrayMisc.class, Misc.class, BindMethodMetaArrayAdvice.class, TestMethodMeta.class); // when test.execute1(); // then // can't compare Class objects directly since they are in different class loaders due to // IsolatedWeavingClassLoader TestMethodMeta testMethodMeta = SomeAspectThreadLocals.isEnabledMethodMeta.get(); assertThat(testMethodMeta.getDeclaringClassName()).isEqualTo(ArrayMisc.class.getName()); assertThat(testMethodMeta.getReturnTypeName()).isEqualTo(void.class.getName()); Class<?> somethingPrivateClass = Class.forName("org.glowroot.agent.weaving.other.ArrayMisc$SomethingPrivate"); Class<?> somethingPrivateArrayClass = Array.newInstance(somethingPrivateClass, 0).getClass(); assertThat(testMethodMeta.getParameterTypeNames()).containsExactly(byte[].class.getName(), Object[][][].class.getName(), somethingPrivateArrayClass.getName()); assertThat(SomeAspectThreadLocals.onBeforeMethodMeta.get()).isEqualTo(testMethodMeta); assertThat(SomeAspectThreadLocals.onReturnMethodMeta.get()).isEqualTo(testMethodMeta); assertThat(SomeAspectThreadLocals.onThrowMethodMeta.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterMethodMeta.get()).isEqualTo(testMethodMeta); } @Test public void shouldBindMethodMetaReturnArray() throws Exception { // given Misc test = newWovenObject(ArrayMisc.class, Misc.class, BindMethodMetaReturnArrayAdvice.class, TestMethodMeta.class); // when test.execute1(); // then // can't compare Class objects directly since they are in different class loaders due to // IsolatedWeavingClassLoader TestMethodMeta testMethodMeta = SomeAspectThreadLocals.isEnabledMethodMeta.get(); assertThat(testMethodMeta.getDeclaringClassName()).isEqualTo(ArrayMisc.class.getName()); assertThat(testMethodMeta.getReturnTypeName()).isEqualTo(int[].class.getName()); assertThat(testMethodMeta.getParameterTypeNames()).isEmpty(); assertThat(SomeAspectThreadLocals.onBeforeMethodMeta.get()).isEqualTo(testMethodMeta); assertThat(SomeAspectThreadLocals.onReturnMethodMeta.get()).isEqualTo(testMethodMeta); assertThat(SomeAspectThreadLocals.onThrowMethodMeta.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterMethodMeta.get()).isEqualTo(testMethodMeta); } // ===================== @BindReturn ===================== @Test public void shouldBindReturn() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindReturnAdvice.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.returnValue.get()).isEqualTo("xyz"); } @Test public void shouldBindPrimitiveReturn() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, BindPrimitiveReturnAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.returnValue.get()).isEqualTo(4); } @Test public void shouldBindAutoboxedReturn() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, BindAutoboxedReturnAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.returnValue.get()).isEqualTo(4); } // ===================== @BindOptionalReturn ===================== @Test public void shouldBindOptionalReturn() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindOptionalReturnAdvice.class, OptionalReturn.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.optionalReturnValue.get().isVoid()).isFalse(); assertThat(SomeAspectThreadLocals.optionalReturnValue.get().getValue()).isEqualTo("xyz"); } @Test public void shouldBindOptionalVoidReturn() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindOptionalVoidReturnAdvice.class, OptionalReturn.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.optionalReturnValue.get().isVoid()).isTrue(); } @Test public void shouldBindOptionalPrimitiveReturn() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, BindOptionalPrimitiveReturnAdvice.class, OptionalReturn.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.optionalReturnValue.get().isVoid()).isFalse(); assertThat(SomeAspectThreadLocals.optionalReturnValue.get().getValue()) .isEqualTo(Integer.valueOf(4)); } // ===================== @BindThrowable ===================== @Test public void shouldBindThrowable() throws Exception { // given Misc test = newWovenObject(ThrowingMisc.class, Misc.class, BindThrowableAdvice.class); // when try { test.execute1(); } catch (Throwable t) { } // then assertThat(SomeAspectThreadLocals.throwable.get()).isNotNull(); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(1); } // ===================== @BindMethodName ===================== @Test public void shouldBindMethodName() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BindMethodNameAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.isEnabledMethodName.get()).isEqualTo("execute1"); assertThat(SomeAspectThreadLocals.onBeforeMethodName.get()).isEqualTo("execute1"); assertThat(SomeAspectThreadLocals.onReturnMethodName.get()).isEqualTo("execute1"); assertThat(SomeAspectThreadLocals.onThrowMethodName.get()).isNull(); assertThat(SomeAspectThreadLocals.onAfterMethodName.get()).isEqualTo("execute1"); } // ===================== change return value ===================== @Test public void shouldChangeReturnValue() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, ChangeReturnAdvice.class); // when CharSequence returnValue = test.executeWithReturn(); // then assertThat(returnValue).isEqualTo("modified xyz:executeWithReturn"); } // ===================== inheritance ===================== @Test public void shouldNotWeaveIfDoesNotOverrideMatch() throws Exception { // given Misc2 test = newWovenObject(BasicMisc.class, Misc2.class, BasicAdvice.class); // when test.execute2(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } // ===================== methodParameters '..' ===================== @Test public void shouldMatchMethodParametersDotDot1() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodParametersDotDotAdvice1.class); // when test.executeWithArgs("one", 2); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } @Test public void shouldNotMatchMethodParametersBadDotDot1() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodParametersBadDotDotAdvice1.class); // when test.executeWithArgs("one", 2); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); } @Test public void shouldMatchMethodParametersDotDot2() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodParametersDotDotAdvice2.class); // when test.executeWithArgs("one", 2); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } @Test public void shouldMatchMethodParametersDotDot3() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodParametersDotDotAdvice3.class); // when test.executeWithArgs("one", 2); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } // ===================== @Pointcut.subTypeRestriction ===================== @Test public void shouldExecuteSubTypeRestrictionAdvice() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, SubTypeRestrictionAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteSubTypeRestrictionAdvice2() throws Exception { // given Misc test = newWovenObject(SubBasicMisc.class, Misc.class, SubTypeRestrictionAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldNotExecuteSubTypeRestrictionAdvice() throws Exception { // given Misc test = newWovenObject(NestingMisc.class, Misc.class, SubTypeRestrictionAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldExecuteSubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice() throws Exception { // given SuperBasic test = newWovenObject(BasicMisc.class, SuperBasic.class, SubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteSubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice2() throws Exception { // given SuperBasic test = newWovenObject(SubBasicMisc.class, SuperBasic.class, SubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldNotExecuteSubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice() throws Exception { // given SuperBasic test = newWovenObject(SuperBasicMisc.class, SuperBasic.class, SubTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldExecuteSubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice() throws Exception { // given Misc test = newWovenObject(SubBasicMisc.class, Misc.class, SubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteSubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice2() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, SubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldNotExecuteSubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice() throws Exception { // given Misc test = newWovenObject(NestingMisc.class, Misc.class, SubTypeRestrictionWhereMethodNotReImplementedInSubSubClassAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } // ===================== @Pointcut.superTypeRestriction ===================== @Test public void shouldExecuteSuperTypeRestrictionAdvice() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, SuperTypeRestrictionAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteSuperTypeRestrictionAdvice2() throws Exception { // given Misc test = newWovenObject(SubBasicMisc.class, Misc.class, SuperTypeRestrictionAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldNotExecuteSuperTypeRestrictionAdvice() throws Exception { // given Misc test = newWovenObject(NestingMisc.class, Misc.class, SuperTypeRestrictionAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldNotExecuteSuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice() throws Exception { // given SuperBasic test = newWovenObject(BasicMisc.class, SuperBasic.class, SuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldNotExecuteSuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice2() throws Exception { // given SuperBasic test = newWovenObject(SubBasicMisc.class, SuperBasic.class, SuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldStillNotExecuteSuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice() throws Exception { // given SuperBasic test = newWovenObject(SuperBasicMisc.class, SuperBasic.class, SuperTypeRestrictionWhereMethodNotReImplementedInSubClassAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldExecuteComplexSuperTypeRestrictedPointcut() throws Exception { // given SubMisc test = newWovenObject(BasicMisc.class, SubMisc.class, ComplexSuperTypeRestrictionAdvice.class); // when test.sub(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } // ===================== annotation-based pointcuts ===================== @Test public void shouldExecuteAnnotationBasedPointcut() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BasicAnnotationBasedAdvice.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteAnotherAnnotationBasedPointcut() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, AnotherAnnotationBasedAdvice.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteAnotherAnnotationButWrongBasedPointcut() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, AnotherAnnotationBasedAdviceButWrong.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } // ===================== throw in lower priority @OnBefore ===================== // motivation for this test: any dangerous code in @OnBefore should occur before calling // transactionService.start..., since @OnAfter will not be called if an exception occurs // however, if there are multiple pointcuts for one method, the dangerous code in @OnBefore // of the lower priority pointcut occurs after the @OnBefore of the higher priority pointcut // and so if the dangerous code in the lower priority pointcut throws an exception, need to make // sure the @OnAfter of the higher priority pointcut is still called @Test public void shouldStillCallOnAfterOfHigherPriorityPointcut() throws Exception { // given // SomeAspectThreadLocals is passed as bridgeable so that the static thread locals will be // accessible for test verification IsolatedWeavingClassLoader isolatedWeavingClassLoader = new IsolatedWeavingClassLoader( Misc.class, SomeAspectThreadLocals.class, IntegerThreadLocal.class); List<Advice> advisors = Lists.newArrayList(); advisors.add(new AdviceBuilder(BasicAdvice.class).build()); advisors.add(new AdviceBuilder(BindThrowableAdvice.class).build()); advisors.add(new AdviceBuilder(ThrowInOnBeforeAdvice.class).build()); advisors.add(new AdviceBuilder(BasicHighOrderAdvice.class).build()); Supplier<List<Advice>> advisorsSupplier = Suppliers.<List<Advice>>ofInstance(ImmutableList.copyOf(advisors)); AnalyzedWorld analyzedWorld = new AnalyzedWorld(advisorsSupplier, ImmutableList.<ShimType>of(), ImmutableList.<MixinType>of()); TransactionRegistry transactionRegistry = mock(TransactionRegistry.class); when(transactionRegistry.getCurrentThreadContextHolder()) .thenReturn(new FastThreadLocal<ThreadContextImpl>().getHolder()); Weaver weaver = new Weaver(advisorsSupplier, ImmutableList.<ShimType>of(), ImmutableList.<MixinType>of(), analyzedWorld, transactionRegistry, new TimerNameCache(), mock(ConfigService.class)); isolatedWeavingClassLoader.setWeaver(weaver); Misc test = isolatedWeavingClassLoader.newInstance(BasicMisc.class, Misc.class); // when RuntimeException exception = null; try { test.execute1(); } catch (RuntimeException e) { exception = e; } // then assertThat(exception.getMessage()).isEqualTo("Abxy"); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.throwable.get().getMessage()).isEqualTo("Abxy"); } // ===================== @Shim ===================== @Test public void shouldShim() throws Exception { // given Misc test = newWovenObject(ShimmedMisc.class, Misc.class, Shimmy.class, Shimmy.class); // when ((Shimmy) test).shimmySetString("another value"); // then assertThat(((Shimmy) test).shimmyGetString()).isEqualTo("another value"); } // ===================== @Mixin ===================== @Test public void shouldMixinToClass() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, HasStringClassMixin.class, HasString.class); // when ((HasString) test).setString("another value"); // then assertThat(((HasString) test).getString()).isEqualTo("another value"); } @Test public void shouldMixinToInterface() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, HasStringInterfaceMixin.class, HasString.class); // when ((HasString) test).setString("another value"); // then assertThat(((HasString) test).getString()).isEqualTo("another value"); } @Test public void shouldMixinOnlyOnce() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, HasStringMultipleMixin.class, HasString.class); // when ((HasString) test).setString("another value"); // then assertThat(((HasString) test).getString()).isEqualTo("another value"); } @Test public void shouldMixinAndCallInitExactlyOnce() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, HasStringClassMixin.class, HasString.class); // when // then assertThat(((HasString) test).getString()).isEqualTo("a string"); } // ===================== static pointcuts ===================== @Test public void shouldWeaveStaticMethod() throws Exception { // given Misc test = newWovenObject(StaticMisc.class, Misc.class, StaticAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } // ===================== primitive args ===================== @Test public void shouldWeaveMethodWithPrimitiveArgs() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, PrimitiveAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } // ===================== wildcard args ===================== @Test public void shouldWeaveMethodWithWildcardArgs() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, PrimitiveWithWildcardAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } @Test public void shouldNotBombWithWithWildcardArg() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, WildMethodAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } // ===================== type name pattern ===================== @Test public void shouldWeaveTypeWithNamePattern() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, ClassNamePatternAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } // ===================== autobox args ===================== @Test public void shouldWeaveMethodWithAutoboxArgs() throws Exception { // given Misc test = newWovenObject(PrimitiveMisc.class, Misc.class, PrimitiveWithAutoboxAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); } // ===================== return type matching ===================== @Test public void shouldMatchMethodReturningVoid() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodReturnVoidAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); } @Test public void shouldMatchMethodReturningCharSequence() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodReturnCharSequenceAdvice.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); } @Test public void shouldNotMatchMethodReturningString() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MethodReturnStringAdvice.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); } @Test public void shouldNotMatchMethodBasedOnReturnType() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, NonMatchingMethodReturnAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); } @Test public void shouldNotMatchMethodBasedOnReturnType2() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, NonMatchingMethodReturnAdvice2.class); // when test.executeWithReturn(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); } // ===================== bridge methods ===================== @Test public void shouldHandleGenericOverride1() throws Exception { // given @SuppressWarnings("unchecked") GenericMisc<String> test = newWovenObject(GenericMiscImpl.class, GenericMisc.class, GenericMiscAdvice.class); // reset thread locals after instantiated BasicMisc, to avoid counting that constructor call SomeAspectThreadLocals.resetThreadLocals(); // when test.execute1(""); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleGenericOverride2() throws Exception { // given @SuppressWarnings("unchecked") GenericMisc<String> test = newWovenObject(GenericMiscImpl.class, GenericMisc.class, GenericMiscAdvice.class); // reset thread locals after instantiated BasicMisc, to avoid counting that constructor call SomeAspectThreadLocals.resetThreadLocals(); // when test.execute2(""); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleConfusingVisibilityBridge() throws Exception { // given @SuppressWarnings("unchecked") GenericMisc<String> test = newWovenObject(GenericAbstractMiscImpl.class, GenericMisc.class, GenericMiscAdvice.class); // reset thread locals after instantiated BasicMisc, to avoid counting that constructor call SomeAspectThreadLocals.resetThreadLocals(); // when test.execute2(5); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldHandleBridgeCallingSuper() throws Exception { // given @SuppressWarnings("unchecked") GenericMisc<String> test = newWovenObject(GenericAbstractMiscImpl.class, GenericMisc.class, GenericMiscAdvice.class); // reset thread locals after instantiated BasicMisc, to avoid counting that constructor call SomeAspectThreadLocals.resetThreadLocals(); // when test.getObject(Long.class); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } // ===================== constructor ===================== @Test public void shouldHandleConstructorPointcut() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BasicMiscConstructorAdvice.class); // reset thread locals after instantiated BasicMisc, to avoid counting that constructor call SomeAspectThreadLocals.resetThreadLocals(); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } // this is just a test to show the (undesirable) behavior of constructor advice not being nested // // see comment on above test and same comment in AdviceMatcher @Test public void shouldVerifyConstructorPointcutsAreNotNested() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BasicMiscAllConstructorAdvice.class); // reset thread locals after instantiated BasicMisc, to avoid counting that constructor call SomeAspectThreadLocals.resetThreadLocals(); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.orderedEvents.get()).containsExactly("isEnabled", "onBefore", "onReturn", "onAfter", "isEnabled", "onBefore", "onReturn", "onAfter"); } @Test public void shouldHandleInheritedMethodFulfillingAnInterface() throws Exception { // given Misc test = newWovenObject(ExtendsAbstractNotMisc.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldNotCrashOnInheritedFinalMethodFulfillingAnInterface() throws Exception { // given Misc test = newWovenObject(ExtendsAbstractNotMiscWithFinal.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then // do not crash with java.lang.VerifyError } @Test public void shouldHandleInheritedMethod() throws Exception { // given SuperBasic test = newWovenObject(BasicMisc.class, SuperBasic.class, SuperBasicAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleInheritedPublicMethodFromPackagePrivateClass() throws Exception { // given Misc test = newWovenObject(ExtendsPackagePrivateMisc.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleSubInheritedMethod() throws Exception { // given SuperBasic test = newWovenObject(BasicMisc.class, SuperBasic.class, SuperBasicAdvice.class); // when test.callSuperBasic(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleSubInheritedFromClassInBootstrapClassLoader() throws Exception { // given Exception test = newWovenObject(SubException.class, Exception.class, ThrowableToStringAdvice.class); // when test.toString(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleInnerClassArg() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BasicWithInnerClassArgAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandleInnerClass() throws Exception { // given Misc test = newWovenObject(BasicMisc.InnerMisc.class, Misc.class, BasicWithInnerClassAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.enabledCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldHandlePointcutWithMultipleMethods() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MultipleMethodsAdvice.class); // when test.execute1(); test.executeWithArgs("one", 2); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(2); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(2); } @Test public void shouldNotTryToWeaveNativeMethods() throws Exception { // given // when newWovenObject(NativeMisc.class, Misc.class, BasicAdvice.class); // then should not bomb } @Test public void shouldNotTryToWeaveAbstractMethods() throws Exception { // given Misc test = newWovenObject(ExtendsAbstractMisc.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then should not bomb } @Test public void shouldNotDisruptInnerTryCatch() throws Exception { // given Misc test = newWovenObject(InnerTryCatchMisc.class, Misc.class, BasicAdvice.class, HasString.class); // when test.execute1(); // then assertThat(test.executeWithReturn()).isEqualTo("caught"); } @Test public void shouldPayAttentionToStaticModifierMatching() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, NonMatchingStaticAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(0); } @Test public void shouldPayAttentionToPublicAndNonStaticModifierMatching() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, MatchingPublicNonStaticAdvice.class); // when test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldNotBomb() throws Exception { // given Misc test = newWovenObject(BasicMisc.class, Misc.class, BrokenAdvice.class); // when test.executeWithArgs("one", 2); // then should not bomb } @Test public void shouldNotBomb2() throws Exception { // given Misc test = newWovenObject(AccessibilityMisc.class, Misc.class, BasicAdvice.class); // when test.execute1(); // then should not bomb } @Test // weaving an interface method that references a concrete class that implements that interface // is supported public void shouldHandleCircularDependency() throws Exception { // given // when newWovenObject(BasicMisc.class, Misc.class, CircularClassDependencyAdvice.class); // then should not bomb } @Test // weaving an interface method that appears twice in a given class hierarchy should only weave // the method once public void shouldHandleInterfaceThatAppearsTwiceInHierarchy() throws Exception { // given // when Misc test = newWovenObject(SubBasicMisc.class, Misc.class, InterfaceAppearsTwiceInHierarchyAdvice.class); test.execute1(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } @Test public void shouldHandleFinalMethodAdvice() throws Exception { // given // when Misc test = newWovenObject(SubBasicMisc.class, Misc.class, FinalMethodAdvice.class); test.executeWithArgs("one", 2); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldWeaveBytecodeWithStackFrames() throws Exception { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); Misc test = newWovenObject(BytecodeWithStackFramesMisc.class, Misc.class, TestBytecodeWithStackFramesAdvice.class); test.executeWithReturn(); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldWeaveBytecodeWithStackFrames2() throws Exception { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); Misc test = newWovenObject(BytecodeWithStackFramesMisc.class, Misc.class, TestBytecodeWithStackFramesAdvice2.class); test.executeWithReturn(); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldWeaveBytecodeWithStackFrames3() throws Exception { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); Misc test = newWovenObject(BytecodeWithStackFramesMisc.class, Misc.class, TestBytecodeWithStackFramesAdvice3.class); test.executeWithReturn(); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldWeaveBytecodeWithStackFrames4() throws Exception { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); Misc test = newWovenObject(BytecodeWithStackFramesMisc.class, Misc.class, TestBytecodeWithStackFramesAdvice4.class); test.executeWithReturn(); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldWeaveBytecodeWithStackFrames5() throws Exception { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); Misc test = newWovenObject(BytecodeWithStackFramesMisc.class, Misc.class, TestBytecodeWithStackFramesAdvice5.class); test.executeWithReturn(); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldWeaveBytecodeWithStackFrames6() throws Exception { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); Misc test = newWovenObject(BytecodeWithStackFramesMisc.class, Misc.class, TestBytecodeWithStackFramesAdvice6.class); test.executeWithReturn(); } @Test // test weaving against jdk 1.7 bytecode with stack frames public void shouldNotBombWithDuplicateFrames() throws Exception { // TODO this test only proves something when -target 1.7 (which currently it never is during // travis build) assumeJdk7(); newWovenObject(DuplicateStackFramesMisc.class, Misc.class, BasicAdvice.class); } @Test public void shouldNotBombWithTroublesomeBytecode() throws Exception { // this actually works with -target 1.6 as long as run using 1.7 jvm since it defines the // troublesome bytecode at runtime as jdk 1.7 bytecode assumeJdk7(); Misc test = newWovenObject(TroublesomeBytecodeMisc.class, Misc.class, TestTroublesomeBytecodeAdvice.class); test.execute1(); } // ===================== test not perfect bytecode ===================== @Test public void shouldExecuteAdviceOnNotPerfectBytecode() throws Exception { // given LazyDefinedClass implClass = GenerateNotPerfectBytecode.generateNotPerfectBytecode(); GenerateNotPerfectBytecode.Test test = newWovenObject(implClass, GenerateNotPerfectBytecode.Test.class, NotPerfectBytecodeAdvice.class); // when test.test1(); test.test2(); test.test3(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(3); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(3); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(3); } @Test public void shouldExecuteAdviceOnMoreNotPerfectBytecode() throws Exception { // given LazyDefinedClass implClass = GenerateMoreNotPerfectBytecode.generateMoreNotPerfectBytecode(false); GenerateMoreNotPerfectBytecode.Test test = newWovenObject(implClass, GenerateMoreNotPerfectBytecode.Test.class, MoreNotPerfectBytecodeAdvice.class); // when test.execute(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } @Test public void shouldExecuteAdviceOnMoreNotPerfectBytecodeVariant() throws Exception { // given LazyDefinedClass implClass = GenerateMoreNotPerfectBytecode.generateMoreNotPerfectBytecode(true); GenerateMoreNotPerfectBytecode.Test test = newWovenObject(implClass, GenerateMoreNotPerfectBytecode.Test.class, MoreNotPerfectBytecodeAdvice.class); // when test.execute(); // then assertThat(SomeAspectThreadLocals.onBeforeCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onReturnCount.get()).isEqualTo(1); assertThat(SomeAspectThreadLocals.onThrowCount.get()).isEqualTo(0); assertThat(SomeAspectThreadLocals.onAfterCount.get()).isEqualTo(1); } public static <S, T extends S> S newWovenObject(Class<T> implClass, Class<S> bridgeClass, Class<?> adviceOrShimOrMixinClass, Class<?>... extraBridgeClasses) throws Exception { // SomeAspectThreadLocals is passed as bridgeable so that the static thread locals will be // accessible for test verification List<Class<?>> bridgeClasses = Lists.newArrayList(); bridgeClasses.add(bridgeClass); bridgeClasses.add(SomeAspectThreadLocals.class); bridgeClasses.add(IntegerThreadLocal.class); bridgeClasses.addAll(Arrays.asList(extraBridgeClasses)); IsolatedWeavingClassLoader isolatedWeavingClassLoader = new IsolatedWeavingClassLoader(bridgeClasses.toArray(new Class<?>[0])); List<Advice> advisors = Lists.newArrayList(); if (adviceOrShimOrMixinClass.isAnnotationPresent(Pointcut.class)) { advisors.add(new AdviceBuilder(adviceOrShimOrMixinClass).build()); } List<MixinType> mixinTypes = Lists.newArrayList(); Mixin mixin = adviceOrShimOrMixinClass.getAnnotation(Mixin.class); if (mixin != null) { mixinTypes.add(MixinType.create(mixin, adviceOrShimOrMixinClass)); } List<ShimType> shimTypes = Lists.newArrayList(); Shim shim = adviceOrShimOrMixinClass.getAnnotation(Shim.class); if (shim != null) { shimTypes.add(ShimType.create(shim, adviceOrShimOrMixinClass)); } Supplier<List<Advice>> advisorsSupplier = Suppliers.<List<Advice>>ofInstance(ImmutableList.copyOf(advisors)); AnalyzedWorld analyzedWorld = new AnalyzedWorld(advisorsSupplier, shimTypes, mixinTypes); TransactionRegistry transactionRegistry = mock(TransactionRegistry.class); when(transactionRegistry.getCurrentThreadContextHolder()) .thenReturn(new FastThreadLocal<ThreadContextImpl>().getHolder()); Weaver weaver = new Weaver(advisorsSupplier, shimTypes, mixinTypes, analyzedWorld, transactionRegistry, new TimerNameCache(), mock(ConfigService.class)); isolatedWeavingClassLoader.setWeaver(weaver); return isolatedWeavingClassLoader.newInstance(implClass, bridgeClass); } public static <S, T extends S> S newWovenObject(LazyDefinedClass toBeDefinedImplClass, Class<S> bridgeClass, Class<?> adviceOrShimOrMixinClass, Class<?>... extraBridgeClasses) throws Exception { // SomeAspectThreadLocals is passed as bridgeable so that the static thread locals will be // accessible for test verification List<Class<?>> bridgeClasses = Lists.newArrayList(); bridgeClasses.add(bridgeClass); bridgeClasses.add(SomeAspectThreadLocals.class); bridgeClasses.add(IntegerThreadLocal.class); bridgeClasses.addAll(Arrays.asList(extraBridgeClasses)); IsolatedWeavingClassLoader isolatedWeavingClassLoader = new IsolatedWeavingClassLoader(bridgeClasses.toArray(new Class<?>[0])); List<Advice> advisors = Lists.newArrayList(); if (adviceOrShimOrMixinClass.isAnnotationPresent(Pointcut.class)) { advisors.add(new AdviceBuilder(adviceOrShimOrMixinClass).build()); } List<MixinType> mixinTypes = Lists.newArrayList(); Mixin mixin = adviceOrShimOrMixinClass.getAnnotation(Mixin.class); if (mixin != null) { mixinTypes.add(MixinType.create(mixin, adviceOrShimOrMixinClass)); } List<ShimType> shimTypes = Lists.newArrayList(); Shim shim = adviceOrShimOrMixinClass.getAnnotation(Shim.class); if (shim != null) { shimTypes.add(ShimType.create(shim, adviceOrShimOrMixinClass)); } Supplier<List<Advice>> advisorsSupplier = Suppliers.<List<Advice>>ofInstance(ImmutableList.copyOf(advisors)); AnalyzedWorld analyzedWorld = new AnalyzedWorld(advisorsSupplier, shimTypes, mixinTypes); TransactionRegistry transactionRegistry = mock(TransactionRegistry.class); when(transactionRegistry.getCurrentThreadContextHolder()) .thenReturn(new FastThreadLocal<ThreadContextImpl>().getHolder()); Weaver weaver = new Weaver(advisorsSupplier, shimTypes, mixinTypes, analyzedWorld, transactionRegistry, new TimerNameCache(), mock(ConfigService.class)); isolatedWeavingClassLoader.setWeaver(weaver); String className = toBeDefinedImplClass.type().getClassName(); isolatedWeavingClassLoader.addManualClass(className, toBeDefinedImplClass.bytes()); @SuppressWarnings("unchecked") Class<T> implClass = (Class<T>) Class.forName(className, false, isolatedWeavingClassLoader); return isolatedWeavingClassLoader.newInstance(implClass, bridgeClass); } private static void assumeJdk7() { Assume.assumeFalse(StandardSystemProperty.JAVA_VERSION.value().startsWith("1.6")); } }