Skip to content

Instantly share code, notes, and snippets.

@ddimtirov
Last active July 27, 2016 03:11
Show Gist options
  • Save ddimtirov/34b85ee3aeeb3052474b0ca9a0cb55ef to your computer and use it in GitHub Desktop.
Save ddimtirov/34b85ee3aeeb3052474b0ca9a0cb55ef to your computer and use it in GitHub Desktop.
Aspect dumping the injection structure of a Dagger component.

Each node corresponds to an injection provider.

Each root node corresponds to a direct call to a @Component method; nesting between { } denotes the provider calls to create the instance.

  • The normal creation nodes look like <class-name>@<hash> created by <factory-class>
  • References to already created objects look like @<class-name>
  • If we have more than one instances of a class, the creation line would be changed to <class-name>@<hash> * <number> instances created by <factory-class>
  • If a provider metnod returned a collection of unknown objects (created outside of Dagger), these will be annotated with (external instance) - careful with the scoping of these.
import org.aspectj.lang.Signature;
import java.util.*;
import java.util.stream.Collectors;
interface DaggerComponentMarker {} // marker, so we can find the children of annotated classes using the pointcut language
public aspect DaggerTracer {
Deque<InjectionRecord> stack = new LinkedList<>();
Set<Object> seen = new HashSet<>();
declare parents : (@Component *) implements DaggerComponentMarker;
pointcut daggerTyped() : execution(* DaggerComponentMarker+.*()); // doesn't work when the component interface is not leaded before the generated class
pointcut daggerNamingConvention() : execution(* *..Dagger*Component+.*()); // so as a fallback we use a naming pattern
pointcut dagger() : (daggerTyped() || daggerNamingConvention()) && !execution(static * *(..));
Object around() : dagger() {
InjectionRecord node = new InjectionRecord(thisJoinPointStaticPart.getSignature());
stack.push(node);
node.instance = proceed();
node.created = seen.add(node.instance);
stack.pop();
Map<Class<?>, Long> seenTypes = seen.stream().collect(Collectors.groupingBy(Object::getClass, Collectors.counting()));
System.out.println(node.format(seenTypes));
return node.instance;
}
Object around() : execution(* Provider.get()) && cflowbelow(dagger()) {
InjectionRecord node = new InjectionRecord(thisJoinPointStaticPart.getSignature());
stack.peek().dependencies.add(node);
stack.push(node);
node.instance = proceed();
node.created = seen.add(node.instance);
stack.pop();
return node.instance;
}
}
class InjectionRecord {
static StringBuilder indent = new StringBuilder();
final Signature method;
final Set<InjectionRecord> dependencies = new HashSet<>();
Object instance;
boolean created;
InjectionRecord(Signature method) {
this.method = method;
}
@Override
public String toString() {
return format(null);
}
public String format(Map<Class<?>, Long> seenTypes) {
StringBuilder sb = new StringBuilder(indent);
format(sb, this, false, seenTypes);
return sb.toString();
}
private StringBuilder format(StringBuilder sb, Object value, boolean created, Map<Class<?>, Long> seenTypes) {
if (value==null) {
sb.append("NULL");
} else if (value instanceof InjectionRecord) {
InjectionRecord that = (InjectionRecord) value;
format(sb, that.instance, that.created, seenTypes);
if (!that.dependencies.isEmpty()) {
sb.append(" {\n");
indent.append(" ");
for (InjectionRecord dependency : that.dependencies) {
sb.append(dependency.format(seenTypes)).append(",\n");
}
indent.setLength(indent.length()-4);
sb.append(indent).append("}");
}
} else if (value instanceof Class) {
Class type = (Class) value;
sb.append(type.getSimpleName());
} else if (value instanceof Collection) {
Collection collection = (Collection) value;
if (collection.isEmpty()) {
sb.append("EMPTY ").append(collection.getClass().getSimpleName());
} else {
sb.append(value.getClass().getSimpleName()).append("[");
for (Object o : collection) {
format(sb, o, false, seenTypes).append(", ");
}
sb.setLength(sb.length() -2);
sb.append("]");
}
} else {
if (!created) sb.append("@");
sb.append(value.getClass().getSimpleName());
if (created) sb.append("@").append(value.hashCode());
if (seenTypes !=null) {
if (seenTypes.containsKey(value.getClass())) {
long count = seenTypes.get(value.getClass());
if (count >1) sb.append(" * ").append(count).append(" instances");
} else {
sb.append(" (external instance)");
}
}
if (created) sb.append(" created by ").append(method.getDeclaringType().getSimpleName());
}
return sb;
}
}
@ManagedTimeSourceProxy {
ManagedTimeSourceProxy@1522975986 created by SimulatedTimeModule_ManagedTimeSourceProxyFactory,
}
@Environment {
Environment@1301763240 created by EnvironmentModule_EnvironmentFactory {
EventBusService@257650296 created by CommunicationModule_EventBusServiceFactory {
NullChannelDecoratorFactory@765420745 created by CommunicationModule_RejectChannelFactoryFactory,
NullChannelDecoratorFactory@356308667 created by CommunicationModule_ChannelFactoryFactory,
@ManagedTimeSourceProxy,
CommandInFlightRegistry@1043882455 created by EnvironmentModule_InFlightRegistryFactory,
FilteringEventPrinter@1198426006 created by CommunicationModule_EventPrinterFactory,
},
SingleInstanceServiceFactory@2111669429 created by EnvironmentModule_ServiceFactoryFactory {
SchedulerService@1875304119 created by EnvironmentModule_SchedulerServiceFactory {
@ManagedTimeSourceProxy,
},
LoggingService@218688965 created by EnvironmentModule_LoggingServiceFactory,
AnalyticsService@99195804 created by EnvironmentModule_AnalyticsServiceFactory {
HashSet[VolumeLimitPriceAnalytics, VolumeCurveAnalyticsService, VolumePriceProfileAnalyticsOnContainer],
HashSet[MyFunction],
HashSet[SampleAnalytics, MyFunctionAnalytics, MACDAnalytics] {
$Proxy28@-1335650596 created by ContainerModule_ExtensionRegistryFactory,
},
},
AlertsService@1489099273 created by EnvironmentModule_AlertsServiceFactory,
ReferenceDataService@1409712092 created by EnvironmentModule_ReferenceDataServiceFactory,
OrderManagementService@2124360754 created by EnvironmentModule_InternalOrderManagementServiceFactory {
OMSStoreConfigurationDefault@1125614861 created by OMSStoreConfigurationModule_OmsStoreConfigurationFactory,
},
ConfigurationService@1600061360 created by EnvironmentModule_ConfigurationServiceFactory,
SystemLifecycleManager@1985011414 created by EnvironmentModule_SystemLifecycleManagerFactory,
MarketDataService@1741618564 created by EnvironmentModule_MarketDataServiceFactory,
},
},
}
@Environment
@Environment
StrategyContainerComponentBuilder@623330465 created by DaggerSimulatedAlgorithmicContainerComponent
@AlgorithmicContainer {
AlgorithmicContainer@1075593808 created by ContainerModule_AlgorithmicContainerFactory {
@CoreStrategyContainer {
CoreStrategyContainer@1875718595 created by ContainerModule_CoreContainerFactory {
StrategyMonitor@1201324747 created by ContainerModule_StrategyMonitorFactory,
StrategyContainerFactory@2083951216 created by ContainerModule_StrategyContainerFactoryFactory {
@StrategyContainerComponentBuilder,
},
StrategyController@1421016152 created by ContainerModule_StrategyControllerFactory,
IndicationDistributor@22179697 created by ContainerModule_IndicationDistributorFactory,
},
},
StrategyContainer@526833889 created by StrategyModule_StrategyContainerFactory {
TradingManager@219396780 created by ContainerModule_TradingManagerFactory {
@OrderManagementService,
},
@CoreStrategyContainer,
@CoreStrategyContainer,
},
Context@1713365029 created by ContainerModule_ContextFactory {
CustomServiceRegistry@646148183 created by ContainerModule_CustomServiceRegistryFactory {
ExtensionRegistryService@891328061 created by ContainerModule_BootServiceFactory {
HashSet[IcebergTacticStrategy, TacticStrategy, AcceptingSpammerStrategy2, AcceptingSpammerStrategy, TacticStrategy, PriceAmendSpammerStrategy, VWAPStrategy, VolumeInlineStrategy, TooManyEventsSpamStrategy, TacticStrategy, TWAPStrategy, TacticStrategy, TacticStrategy, Sasuke, IcebergStrategy, SmartPegStrategy, WrongTickSizeSpamStrategy, TacticStrategy, TacticStrategy, TacticStrategy, SplitCancelSpammerStrategy, TacticStrategy],
HashSet[AlgoOrderStrategy],
HashSet[NonNegativePrice, NonNegativeQuantity, NonNegativeQuantityOnAmend, DisplayQuantityProvided, StrategyParameterProvided, PricePegExpressionValid, RefillProvided, LayerTypeValid, NonNegativePriceOffset],
HashSet[DefaultStrategyOrderValidationHandler],
},
},
},
AssemblyLineController@1137401656 created by ContainerModule_AssemblyLineFactory {
SingleInstanceLayerFactory@1561668557 created by ContainerModule_FunctionalLayerFactoryFactory {
StrategyViewRegister@1175146719 created by ContainerModule_OrderBookRegisterFactory,
BasicByteSegmentAllocator@1240727361 created by ContainerModule_ByteSegmentAllocatorFactory,
@ConstraintsManager {
ConstraintsManager@1475331837 created by ContainerModule_AConstraintsManagerFactory,
},
},
},
},
}
@ManagedTimeSourceProxy {
@ManagedTimeSourceProxy,
}
@Environment
@Environment
@Sandbox {
Sandbox@1933471223 created by SandboxModule_SandboxFactory {
@AlgorithmicContainer,
ExchangeSimulator@1445534206 created by SandboxModule_ExchangeSimulatorFactory {
@Environment,
},
@Environment,
ConfigurationInjector@2038585029 created by SandboxModule_ConfigInjectorFactory {
@Environment,
},
CompositeDriverContainer@1200812313 created by DriverModule_DriverContainerFactory {
HashSet[@QuadrantDriverContainer, @AnalyticsServerDriverContainer] {
QuadrantDriverContainerFactory@491738374 created by DriverModule_DriverContainerFactoryFactory,
@ManagedTimeSourceProxy,
AnalyticsServerDriverContainerFactory@762722278 created by DriverModule_AnalyticsServerDriverContainerFactoryFactory {
EMPTY HashSet,
HashSet[MyFunction],
HashSet[VolumeCurveAnalyticsOnServer, VolumePriceProfileAnalyticsOnServer, VolumePriceProfileAnalyticsOnContainer],
},
@Environment,
},
},
@ManagedTimeSourceProxy,
SandboxRefDataInjector@406183058 created by SandboxModule_RefDataInjectorFactory {
@Environment,
},
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment