问:
Classpath problems while Instrumenting Springboot application
I have a springboot application which I'm trying to instrument using bytebuddy. I'm running into classpath issues which I'm not able to understand.

Firstly, the following is other literature on this:

https://github.com/raphw/byte-buddy/issues/473

https://github.com/raphw/byte-buddy/issues/87

Unable to instrument apache httpclient using javaagent for spring boot uber jar application

https://github.com/raphw/byte-buddy/issues/109

https://github.com/raphw/byte-buddy/issues/473

https://github.com/raphw/byte-buddy/issues/489

https://github.com/spring-projects/spring-boot/issues/4868

https://github.com/alibaba/transmittable-thread-local/issues/161

Problem is that Spring-boot bundles the application into one uber-jar, which contains other jars inside it

A thing to note here is, that if I run the application using IntelliJ, it doesn't use the uber-jar and runs via main class with a bunch of jars as classpath arguments.

Due to this difference, When running via uber-jar(java -jar target/demo-0.0.1-SNAPSHOT.jar), some classes are not available at the time the Agent runs. The classes are loadable at the time of application main, as spring-boot uses its own classloader, which is created at some time b/w agent and application main methods.

I'll describe the behaviour at various points of time below:

At time of PreMain of Agent

Thread.currentThread().getContextClassLoader() = Launcher$AppClassLoader

Agent.class.classLoader = Launcher$AppClassLoader

Class.forName("org.springframework.web.servlet.HandlerAdapter") => ClassNotFoundException

Class.forName("javax.servlet.http.HttpServletRequest") => ClassNotFoundException

Both spring and javax classes are not loaded as they are not directly in the classpath as per the App Classloader. It's part of an inner jar, something like app.jar!/BOOT-INF/lib/some.jar
App Classloader won't be able to load this.

At time of Main of Application Class

Thread.currentThread().getContextClassLoader() = org.springframework.boot.loader.LaunchedURLClassLoader

DemoApplication.class.classloader = same as above

Class.forName("org.springframework.web.servlet.HandlerAdapter") => loads successfully

Same for javax class, loads successfully.

After loading, Class.forName("javax.servlet.http.HttpServletRequest").classLoader is also the same LaunchedURLClassLoader.

At the time of builder.visit call (when bytebuddy is modifying the class definitions)

Code:

I have two classes, SpringBootInterceptor (which contains the intercept method) and SpringBootInterceptorOne (which contains the entry and exit method)

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    return agentBuilder
      .type(isSubTypeOf(HandlerAdapter.class))
      .transform((builder, typeDescription, classLoader, module) ->
        builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
      );
  }

```

<p>The function <code>intercept()</code> is called in the premain path. </p>

<p>The function <code>visit</code> is called when the type is actually attempted to load. At that point bytebuddy tris to intercept those methods and modify bytecode. </p>

<p>In the current version of this code, the function <code>intercept()</code> throws <code>ClassNotFoundException</code> and interception doesn't happen. </p>

<pre class="lang-java prettyprint-override"><code>Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerAdapter
</code>```

So, I tried to change the code, to the following:

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    return agentBuilder
//      .type(isSubTypeOf(HandlerAdapter.class))
      .type(not(isInterface())
        .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
      .transform((builder, typeDescription, classLoader, module) ->
        builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
      );
  }
```

<p>Here, basically loading the class lazily.
Helper functions from datadog: </p>

<p>https://github.com/DataDog/dd-trace-java/blob/master/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ByteBuddyElementMatchers.java</p>

<p>After doing this, the <code>intercept</code> function doesn't fail, but the <code>visit()</code> function behaves strangely:</p>

<pre class="lang-java prettyprint-override"><code>java.lang.IllegalStateException: Could not locate class file for my.package.name.SpringBootInterceptorOne
    at net.bytebuddy.dynamic.ClassFileLocator$Resolution$Illegal.resolve(ClassFileLocator.java:118)
    at net.bytebuddy.asm.Advice.to(Advice.java:431)
    at net.bytebuddy.asm.Advice.to(Advice.java:400)
    at net.bytebuddy.asm.Advice.to(Advice.java:375)
    at net.bytebuddy.asm.Advice.to(Advice.java:361)
    at my.package.name.SpringBootInterceptor.lambda$intercept$0(SpringBootInterceptor.java:30)
    at net.bytebuddy.agent.builder.AgentBuilder$Transformer$Compound.transform(AgentBuilder.java:2612)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:10117)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10494)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10457)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1500(AgentBuilder.java:10223)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10833)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10780)
    at java.security.AccessController.doPrivileged(Native Method)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10380)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:757)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethods(Class.java:1975)
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:358)
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:414)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod$2(AbstractAutowireCapableBeanFactory.java:743)
    at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:742)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:649)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1604)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:520)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:491)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:230)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:223)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:213)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:167)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:142)
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
    at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:184)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    at com.example.demo.DemoApplication.main(DemoApplication.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)

</code>```

At this point,

Thread.currentThread().getContextClassLoader() => LaunchedURLClassLoader

SpringBootInterceptor.class.getClassLoader() = null

Typing SpringBootInterceptor.class in the debugger window doesn't fail, but

Class.forName("my.package.name.SpringBootInterceptorOne") => NoClassDefFound

Next, I tried the following:

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return agentBuilder
//      .type(isSubTypeOf(HandlerAdapter.class))
      .type(not(isInterface())
        .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
      .transform((builder, typeDescription, classLoader, module) -> {
          try {
            Class<?> claz = Thread.currentThread().getContextClassLoader().loadClass("my.package.name.SpringBootInterceptorOne");
            return builder.visit(Advice.to(claz, claz,
              new ClassFileLocator.Compound(ClassFileLocator.ForClassLoader.of(cl),
              ClassFileLocator.ForClassLoader.of(Thread.currentThread().getContextClassLoader())
              )).on(named("handle").and(isMethod())));
          } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return builder;
          }
        }
      );
  }

```

<p>This causes the interceptor to be "installed". The entry and exit methods are called okay. But casting the arguments to proper types gives error for the types of the arguments</p>

<pre class="lang-java prettyprint-override"><code>exit spring boot
[Ljava.lang.Object;@c83066a
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
    at my.package.name.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:36)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

</code>```

Here is SpringBootInterceptorOne for reference:

  @Advice.OnMethodExit
  static void exit(@Advice.Origin final Executable executable,
                   @Advice.This Object handlerAdapter,
                   @Advice.AllArguments Object[] arguments,
                   @Advice.Enter final TimerContext ctx) {
//      final long duration = ctx.getDuration();
    System.out.println("exit spring boot");
    String e = getEndpoint(arguments);
    System.out.println(e);
  }

  public static String getEndpoint(Object[] arguments) {
    System.out.println(arguments);
    HttpServletRequest request = (HttpServletRequest) arguments[0];
    HandlerMethod  handler = (HandlerMethod) arguments[2];
    return "ad";
  }
```

<p>UPDATE:</p>

<p>As per the advice offered in an answer, I tried the following:</p>

<pre class="lang-java prettyprint-override"><code>  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    return agentBuilder
//      .type(isSubTypeOf(HandlerAdapter.class))
      .type(not(isInterface())
        .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
      .transform(new AgentBuilder.Transformer.ForAdvice()
        .include(SpringBootInterceptorOne.class.getClassLoader())
        .include(getClass().getClassLoader())
        .advice(named("handle"), SpringBootInterceptorOne.class.getName())
      );
  }

</code>```

It again throws Error:

java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
    at io.signoz.interceptors.http.server.springboot.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:37) ~[na:na]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_242]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_242]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_242]

```

答:
The problem is that the advice class will be loaded on the system class loader as a part of the agent whereas the actual application code is loaded on a sub-class loader that is not visible to the system class loader. This situation does not change if you load your agent on the boot loader either. Therefore, the agent cannot load the HttpServletRequest class which is part of the uber-jar.

This is a typical problem with agents and Byte Buddy has a standard way to circumvent it by using a Transformer.ForAdvice instance instead of using the Advice class directly. Byte Buddy then creates a virtual class loader hierarchy that considers classes represented by both class loaders.

Update: The problem is that you are calling down to your interceptor that is defined in the system class loader where the class in question is not available. The annotated code will be inlined but the invoked method will not. If you copy-pasted the code into the annotated method, the behavior is as you'd expect it. Byte Buddy uses the annotated code as template and reuses a lot of information emitted by javac to guarantee a speedy conversion. Therefore, the library cannot simply copy the method and should rather feed the entire method body to javac.

Body:
I have a springboot application which I'm trying to instrument using bytebuddy. I'm running into classpath issues which I'm not able to understand.

Firstly, the following is other literature on this:

https://github.com/raphw/byte-buddy/issues/473

https://github.com/raphw/byte-buddy/issues/87

Unable to instrument apache httpclient using javaagent for spring boot uber jar application

https://github.com/raphw/byte-buddy/issues/109

https://github.com/raphw/byte-buddy/issues/473

https://github.com/raphw/byte-buddy/issues/489

https://github.com/spring-projects/spring-boot/issues/4868

https://github.com/alibaba/transmittable-thread-local/issues/161

Problem is that Spring-boot bundles the application into one uber-jar, which contains other jars inside it

A thing to note here is, that if I run the application using IntelliJ, it doesn't use the uber-jar and runs via main class with a bunch of jars as classpath arguments.

Due to this difference, When running via uber-jar(java -jar target/demo-0.0.1-SNAPSHOT.jar), some classes are not available at the time the Agent runs. The classes are loadable at the time of application main, as spring-boot uses its own classloader, which is created at some time b/w agent and application main methods.

I'll describe the behaviour at various points of time below:

At time of PreMain of Agent

Thread.currentThread().getContextClassLoader() = Launcher$AppClassLoader

Agent.class.classLoader = Launcher$AppClassLoader

Class.forName("org.springframework.web.servlet.HandlerAdapter") => ClassNotFoundException

Class.forName("javax.servlet.http.HttpServletRequest") => ClassNotFoundException

Both spring and javax classes are not loaded as they are not directly in the classpath as per the App Classloader. It's part of an inner jar, something like app.jar!/BOOT-INF/lib/some.jar
App Classloader won't be able to load this.

At time of Main of Application Class

Thread.currentThread().getContextClassLoader() = org.springframework.boot.loader.LaunchedURLClassLoader

DemoApplication.class.classloader = same as above

Class.forName("org.springframework.web.servlet.HandlerAdapter") => loads successfully

Same for javax class, loads successfully.

After loading, Class.forName("javax.servlet.http.HttpServletRequest").classLoader is also the same LaunchedURLClassLoader.

At the time of builder.visit call (when bytebuddy is modifying the class definitions)

Code:

I have two classes, SpringBootInterceptor (which contains the intercept method) and SpringBootInterceptorOne (which contains the entry and exit method)

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    return agentBuilder
      .type(isSubTypeOf(HandlerAdapter.class))
      .transform((builder, typeDescription, classLoader, module) ->
        builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
      );
  }

The function intercept() is called in the premain path.

The function visit is called when the type is actually attempted to load. At that point bytebuddy tris to intercept those methods and modify bytecode.

In the current version of this code, the function intercept() throws ClassNotFoundException and interception doesn't happen.

Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerAdapter

So, I tried to change the code, to the following:

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    return agentBuilder
//      .type(isSubTypeOf(HandlerAdapter.class))
      .type(not(isInterface())
        .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
      .transform((builder, typeDescription, classLoader, module) ->
        builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
      );
  }

Here, basically loading the class lazily.
Helper functions from datadog:

https://github.com/DataDog/dd-trace-java/blob/master/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ByteBuddyElementMatchers.java

After doing this, the intercept function doesn't fail, but the visit() function behaves strangely:

java.lang.IllegalStateException: Could not locate class file for my.package.name.SpringBootInterceptorOne
    at net.bytebuddy.dynamic.ClassFileLocator$Resolution$Illegal.resolve(ClassFileLocator.java:118)
    at net.bytebuddy.asm.Advice.to(Advice.java:431)
    at net.bytebuddy.asm.Advice.to(Advice.java:400)
    at net.bytebuddy.asm.Advice.to(Advice.java:375)
    at net.bytebuddy.asm.Advice.to(Advice.java:361)
    at my.package.name.SpringBootInterceptor.lambda$intercept$0(SpringBootInterceptor.java:30)
    at net.bytebuddy.agent.builder.AgentBuilder$Transformer$Compound.transform(AgentBuilder.java:2612)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:10117)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10494)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10457)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1500(AgentBuilder.java:10223)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10833)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10780)
    at java.security.AccessController.doPrivileged(Native Method)
    at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10380)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:757)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethods(Class.java:1975)
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:358)
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:414)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod$2(AbstractAutowireCapableBeanFactory.java:743)
    at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:742)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:649)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1604)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:520)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:491)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:230)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:223)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:213)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:167)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:142)
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
    at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:184)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    at com.example.demo.DemoApplication.main(DemoApplication.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)

At this point,

Thread.currentThread().getContextClassLoader() => LaunchedURLClassLoader

SpringBootInterceptor.class.getClassLoader() = null

Typing SpringBootInterceptor.class in the debugger window doesn't fail, but

Class.forName("my.package.name.SpringBootInterceptorOne") => NoClassDefFound

Next, I tried the following:

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return agentBuilder
//      .type(isSubTypeOf(HandlerAdapter.class))
      .type(not(isInterface())
        .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
      .transform((builder, typeDescription, classLoader, module) -> {
          try {
            Class<?> claz = Thread.currentThread().getContextClassLoader().loadClass("my.package.name.SpringBootInterceptorOne");
            return builder.visit(Advice.to(claz, claz,
              new ClassFileLocator.Compound(ClassFileLocator.ForClassLoader.of(cl),
              ClassFileLocator.ForClassLoader.of(Thread.currentThread().getContextClassLoader())
              )).on(named("handle").and(isMethod())));
          } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return builder;
          }
        }
      );
  }

This causes the interceptor to be "installed". The entry and exit methods are called okay. But casting the arguments to proper types gives error for the types of the arguments

exit spring boot
[Ljava.lang.Object;@c83066a
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
    at my.package.name.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:36)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

Here is SpringBootInterceptorOne for reference:

  @Advice.OnMethodExit
  static void exit(@Advice.Origin final Executable executable,
                   @Advice.This Object handlerAdapter,
                   @Advice.AllArguments Object[] arguments,
                   @Advice.Enter final TimerContext ctx) {
//      final long duration = ctx.getDuration();
    System.out.println("exit spring boot");
    String e = getEndpoint(arguments);
    System.out.println(e);
  }

  public static String getEndpoint(Object[] arguments) {
    System.out.println(arguments);
    HttpServletRequest request = (HttpServletRequest) arguments[0];
    HandlerMethod  handler = (HandlerMethod) arguments[2];
    return "ad";
  }

UPDATE:

As per the advice offered in an answer, I tried the following:

  @Override
  public AgentBuilder intercept(AgentBuilder agentBuilder) {
    return agentBuilder
//      .type(isSubTypeOf(HandlerAdapter.class))
      .type(not(isInterface())
        .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
      .transform(new AgentBuilder.Transformer.ForAdvice()
        .include(SpringBootInterceptorOne.class.getClassLoader())
        .include(getClass().getClassLoader())
        .advice(named("handle"), SpringBootInterceptorOne.class.getName())
      );
  }

It again throws Error:

java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
    at io.signoz.interceptors.http.server.springboot.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:37) ~[na:na]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_242]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_242]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_242]


来源: stackexchange

问:
Converting jni::sys::JNIEnv to JNINativeInterface defined in ffi
I am following up on Casting a borrowed reference with a lifetime to a raw pointer in Rust, which solved the wrong problem.

Please consider the following code:

extern crate jni;
extern crate ffi;

use jni::JNIEnv;
use jni::objects::JClass;
use jni::sys::{jint, jlong, jobject};

struct CameraAppEngine {
    _env: *mut jni::sys::JNIEnv,
    _width: i32,
    _height: i32
}

impl CameraAppEngine {
    pub fn new(_env: *mut jni::sys::JNIEnv, _width: i32, _height: i32) -> CameraAppEngine {
        CameraAppEngine { _env, _width, _height }
    }

    pub fn create_camera_session(&mut self, surface: jobject) {
        // error!
        let window = ffi::ANativeWindow_fromSurface(self._env, surface);
    }
}

fn app_engine_create(env: &JNIEnv, width: i32, height: i32) -> *mut CameraAppEngine {
    let engine = CameraAppEngine::new(env.get_native_interface(), width, height);
    Box::into_raw(Box::new(engine))
}

#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_createCamera(env: JNIEnv<'static>, _: JClass, width:jint, height:jint) -> jlong {
    app_engine_create(&env, width, height) as jlong
}

#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_onPreviewSurfaceCreated(_: JNIEnv, _: JClass, engine_ptr:jlong, surface:jobject) {
    let mut app = unsafe { Box::from_raw(engine_ptr as *mut CameraAppEngine) };
    app.create_camera_session(surface);
}
```

<p>And in the <code>ffi</code> crate we have:</p>

<pre class="lang-rust prettyprint-override"><code>extern "C" {
    pub fn ANativeWindow_fromSurface(env: *mut JNIEnv, surface: jobject) -> *mut ANativeWindow;
}
</code>```

This results in:

error[E0308]: mismatched types
--> native_app/src/lib.rs:24:53
|
|         let window = ffi::ANativeWindow_fromSurface(self._env, surface);
|                                                     ^^^^^^^^^ expected struct `ffi::JNINativeInterface`, found struct `jni::sys::JNINativeInterface_`
|
= note: expected raw pointer `*mut *const ffi::JNINativeInterface`
            found raw pointer `*mut *const jni::sys::JNINativeInterface_`

error[E0308]: mismatched types
--> native_app/src/lib.rs:24:64
|
|         let window = ffi::ANativeWindow_fromSurface(self._env, surface);
|                                                                ^^^^^^^ expected enum `std::ffi::c_void`, found enum `jni::sys::_jobject`
|
= note: expected raw pointer `*mut std::ffi::c_void`
            found raw pointer `*mut jni::sys::_jobject`
```

<p>The problem is that the JNIEnv type expected by <code>ANativeWindow_fromSurface</code> is actually unrelated to <code>jni::sys::JNIEnv</code> entirely.</p>

<p>It's defined in <code>ffi</code> like so:</p>

<pre class="lang-rust prettyprint-override"><code>pub type JNIEnv = *const JNINativeInterface;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct JNINativeInterface {
    pub reserved0: *mut ::std::os::raw::c_void,
    pub reserved1: *mut ::std::os::raw::c_void,
    pub reserved2: *mut ::std::os::raw::c_void,
    pub reserved3: *mut ::std::os::raw::c_void,
    pub GetVersion: ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv) -> jint>,
    pub DefineClass: ::std::option::Option<
        unsafe extern "C" fn(
            arg1: *mut JNIEnv,
            arg2: *const ::std::os::raw::c_char,
            arg3: jobject,
            arg4: *const jbyte,
            arg5: jsize,
        ) -> jclass,
    >,
    pub FindClass: ::std::option::Option<
        unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: *const ::std::os::raw::c_char) -> jclass,
    >,
    pub FromReflectedMethod:
        ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jmethodID>,
    pub FromReflectedField:
        ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jfieldID>,
    pub ToReflectedMethod: ::std::option::Option<
        unsafe extern "C" fn(
            arg1: *mut JNIEnv,
            arg2: jclass,
            arg3: jmethodID,
            arg4: jboolean,
        ) -> jobject,
    >
    // etc...
}
</code>```

Given the glue code shown in the example, how do I get a valid reference to ffi::JNIEnv so that I may pass it to the ANativeWindow_fromSurface method. Bonus points if you give advice on converting jni::sys::jobject to *mut std::os::raw::c_void (lifetime concerns, null pointers, etc.).

Full source to ffi definitions

Here is the basic helloworld implementation I used to prove the concept in the accepted answer:

use std::ffi::{CString, CStr};
use std::os::raw::{c_char};

/// Expose the JNI interface for android below
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
    extern crate ffi;

    use super::*;
    use self::ffi::{JNIEnv, jclass, jstring, jlong};

    #[derive(Debug)]
    struct AppEngine {
        greeting: *mut c_char
    }

    unsafe fn rust_greeting(app: *mut AppEngine) -> *mut c_char {
        let app = Box::from_raw(app);
        app.greeting
    }

    /// Constructs an AppEngine object.
    fn rust_engine_create(to: *const c_char) -> *mut AppEngine {
        let c_str = unsafe { CStr::from_ptr(to) };
        let recipient = match c_str.to_str() {
            Err(_) => "there",
            Ok(string) => string,
        };

        let greeting = CString::new("Hello ".to_owned() + recipient).unwrap().into_raw();

        let app = AppEngine{greeting: greeting};
        Box::into_raw(Box::new(app))
    }

    /// Destroys an AppEngine object previously constructed using `rust_engine_create()`.
    unsafe fn rust_engine_destroy(app: *mut AppEngine) {
        drop(Box::from_raw(app))
    }

    #[no_mangle]
    pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_greeting(env: &mut JNIEnv, _: jclass, app_ptr: jlong) -> jstring {
        let app = app_ptr as *mut AppEngine;
        let new_string = env.as_ref().unwrap().NewStringUTF.unwrap();
        new_string(env, rust_greeting(app))
    }

    #[no_mangle]
    pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_createNativeApp(env: &mut JNIEnv, _: jclass, java_pattern: jstring) -> jlong {
        let get_string_chars = env.as_ref().unwrap().GetStringChars.unwrap();
        let is_copy = 0 as *mut u8;
        rust_engine_create(get_string_chars(env, java_pattern, is_copy) as *const c_char ) as jlong
    }

    #[no_mangle]
    pub unsafe extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_destroyNativeApp(_: JNIEnv, _: jclass, app_ptr: jlong) {
        let app = app_ptr as *mut AppEngine;
        rust_engine_destroy(app)
    }
}
```

This is just a proof of concept. More care should be taken when casting raw pointers about. Also see notes about Box::leak in the accepted answer.

答:
A JNIEnv is a pointer to a struct used for communication between Java and native code. This communication ABI is implemented by pretty much every JVM(and android). There are multiple versions of the aforementioned structs, which is what the GetVersion field is for.

It seems to me that you are using an external jni crate along with your own ffi crate generated from this wrapper. I would expect your ffi crate to be the most correct since it is using android headers, instead of the standard JVM headers which a most likely being used by the jni crate.

One last note Box::from_raw(engine_ptr as *mut CameraAppEngine), creates a box which will free the memory located at engine_ptr. This is likely not what you want. Consider using Box::leak to leak the created Box and avoid use after frees.

ContentLicense: CC BY-SA 4.0

Body:
I am following up on Casting a borrowed reference with a lifetime to a raw pointer in Rust, which solved the wrong problem.

Please consider the following code:

extern crate jni;
extern crate ffi;

use jni::JNIEnv;
use jni::objects::JClass;
use jni::sys::{jint, jlong, jobject};

struct CameraAppEngine {
    _env: *mut jni::sys::JNIEnv,
    _width: i32,
    _height: i32
}

impl CameraAppEngine {
    pub fn new(_env: *mut jni::sys::JNIEnv, _width: i32, _height: i32) -> CameraAppEngine {
        CameraAppEngine { _env, _width, _height }
    }

    pub fn create_camera_session(&mut self, surface: jobject) {
        // error!
        let window = ffi::ANativeWindow_fromSurface(self._env, surface);
    }
}

fn app_engine_create(env: &JNIEnv, width: i32, height: i32) -> *mut CameraAppEngine {
    let engine = CameraAppEngine::new(env.get_native_interface(), width, height);
    Box::into_raw(Box::new(engine))
}

#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_createCamera(env: JNIEnv<'static>, _: JClass, width:jint, height:jint) -> jlong {
    app_engine_create(&env, width, height) as jlong
}

#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_onPreviewSurfaceCreated(_: JNIEnv, _: JClass, engine_ptr:jlong, surface:jobject) {
    let mut app = unsafe { Box::from_raw(engine_ptr as *mut CameraAppEngine) };
    app.create_camera_session(surface);
}

And in the ffi crate we have:

extern "C" {
    pub fn ANativeWindow_fromSurface(env: *mut JNIEnv, surface: jobject) -> *mut ANativeWindow;
}

This results in:

error[E0308]: mismatched types
--> native_app/src/lib.rs:24:53
|
|         let window = ffi::ANativeWindow_fromSurface(self._env, surface);
|                                                     ^^^^^^^^^ expected struct `ffi::JNINativeInterface`, found struct `jni::sys::JNINativeInterface_`
|
= note: expected raw pointer `*mut *const ffi::JNINativeInterface`
            found raw pointer `*mut *const jni::sys::JNINativeInterface_`

error[E0308]: mismatched types
--> native_app/src/lib.rs:24:64
|
|         let window = ffi::ANativeWindow_fromSurface(self._env, surface);
|                                                                ^^^^^^^ expected enum `std::ffi::c_void`, found enum `jni::sys::_jobject`
|
= note: expected raw pointer `*mut std::ffi::c_void`
            found raw pointer `*mut jni::sys::_jobject`

The problem is that the JNIEnv type expected by ANativeWindow_fromSurface is actually unrelated to jni::sys::JNIEnv entirely.

It's defined in ffi like so:

pub type JNIEnv = *const JNINativeInterface;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct JNINativeInterface {
    pub reserved0: *mut ::std::os::raw::c_void,
    pub reserved1: *mut ::std::os::raw::c_void,
    pub reserved2: *mut ::std::os::raw::c_void,
    pub reserved3: *mut ::std::os::raw::c_void,
    pub GetVersion: ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv) -> jint>,
    pub DefineClass: ::std::option::Option<
        unsafe extern "C" fn(
            arg1: *mut JNIEnv,
            arg2: *const ::std::os::raw::c_char,
            arg3: jobject,
            arg4: *const jbyte,
            arg5: jsize,
        ) -> jclass,
    >,
    pub FindClass: ::std::option::Option<
        unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: *const ::std::os::raw::c_char) -> jclass,
    >,
    pub FromReflectedMethod:
        ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jmethodID>,
    pub FromReflectedField:
        ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jfieldID>,
    pub ToReflectedMethod: ::std::option::Option<
        unsafe extern "C" fn(
            arg1: *mut JNIEnv,
            arg2: jclass,
            arg3: jmethodID,
            arg4: jboolean,
        ) -> jobject,
    >
    // etc...
}

Given the glue code shown in the example, how do I get a valid reference to ffi::JNIEnv so that I may pass it to the ANativeWindow_fromSurface method. Bonus points if you give advice on converting jni::sys::jobject to *mut std::os::raw::c_void (lifetime concerns, null pointers, etc.).

Full source to ffi definitions

Here is the basic helloworld implementation I used to prove the concept in the accepted answer:

use std::ffi::{CString, CStr};
use std::os::raw::{c_char};

/// Expose the JNI interface for android below
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
    extern crate ffi;

    use super::*;
    use self::ffi::{JNIEnv, jclass, jstring, jlong};

    #[derive(Debug)]
    struct AppEngine {
        greeting: *mut c_char
    }

    unsafe fn rust_greeting(app: *mut AppEngine) -> *mut c_char {
        let app = Box::from_raw(app);
        app.greeting
    }

    /// Constructs an AppEngine object.
    fn rust_engine_create(to: *const c_char) -> *mut AppEngine {
        let c_str = unsafe { CStr::from_ptr(to) };
        let recipient = match c_str.to_str() {
            Err(_) => "there",
            Ok(string) => string,
        };

        let greeting = CString::new("Hello ".to_owned() + recipient).unwrap().into_raw();

        let app = AppEngine{greeting: greeting};
        Box::into_raw(Box::new(app))
    }

    /// Destroys an AppEngine object previously constructed using `rust_engine_create()`.
    unsafe fn rust_engine_destroy(app: *mut AppEngine) {
        drop(Box::from_raw(app))
    }

    #[no_mangle]
    pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_greeting(env: &mut JNIEnv, _: jclass, app_ptr: jlong) -> jstring {
        let app = app_ptr as *mut AppEngine;
        let new_string = env.as_ref().unwrap().NewStringUTF.unwrap();
        new_string(env, rust_greeting(app))
    }

    #[no_mangle]
    pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_createNativeApp(env: &mut JNIEnv, _: jclass, java_pattern: jstring) -> jlong {
        let get_string_chars = env.as_ref().unwrap().GetStringChars.unwrap();
        let is_copy = 0 as *mut u8;
        rust_engine_create(get_string_chars(env, java_pattern, is_copy) as *const c_char ) as jlong
    }

    #[no_mangle]
    pub unsafe extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_destroyNativeApp(_: JNIEnv, _: jclass, app_ptr: jlong) {
        let app = app_ptr as *mut AppEngine;
        rust_engine_destroy(app)
    }
}

This is just a proof of concept. More care should be taken when casting raw pointers about. Also see notes about Box::leak in the accepted answer.


问:
Java: How to @SuppressWarnings unreachable code?
Sometimes when you are debugging, you have unreachable code fragment. Is there anyway to suppress the warning?</p>

答:
As Cletus tells us,

It depends on your IDE or compiler.

That said, at least for Eclipse, there is not a way to do this. With my Eclipse configuration, unreachable code causes a compile-time error, not just a warning. Also note this is different from "dead code," e.g.

```<code>if (false)
{
    // dead code here
}
</code>```

for which Eclipse (by default) emits a warning, not an error.

ContentLicense: CC BY-SA 3.0

Body:
As Cletus tells us,

It depends on your IDE or compiler.

That said, at least for Eclipse, there is not a way to do this. With my Eclipse configuration, unreachable code causes a compile-time error, not just a warning. Also note this is different from "dead code," e.g.

if (false)
{
    // dead code here
}

for which Eclipse (by default) emits a warning, not an error.


问:
Abstract classes and Polymorphism - how are additional methods and properties usually handled?
Imagine a rental company that has cars for the company to use internally and trucks to rent. The cars use gas and the trucks use diesel. The trucks have additional things that they do that cars do not - they are rented. So I have the following code:

```<code>abstract class Vehicle
{
    public abstract FuelType Fuel();
}

class Car : Vehicle
{
    public override FuelType Fuel()
    {
        return FuelType.Gas;
    }
}

class Truck : Vehicle
{
    public override FuelType Fuel()
    {
        return FuelType.Diesel;
    }

    //Not in base class or Car class
    public List<Rental> Rentals()
    {
        return new List<Rental>();
    }
}

class Rental
{
      //...some stuff here
}

enum FuelType
{
    Gas,
    Diesel
}
</code>```

What is normally done when the child classes have additional methods and properties? Example:

```<code>        List<Vehicle> vehicles = new List<Vehicle>() { };

        vehicles.Add(new Car());
        vehicles.Add(new Truck());

        foreach (var vehicle in vehicles)
        {
            Console.WriteLine(vehicle.Fuel().ToString());

            //Pseudocode here:
            if(vehicle.GetType() is Truck)
            {
                //Provide rental information
                Truck truck = (Truck)vehicle;
                truck.ProvideSomeInfo();
            }
        }
</code>```

I get how polymorphism works when you have classes that have all the same methods, properties, fields, etc. What is normally done when you need to work with the base class AND you need to work with additional methods, fields, properties that all the children do not share?

All the abstract tutorials that I have found just show the simpler case when all the children have the same sets of methods, properties, fields.

答:
in your case, using interface would be more appropriate.

you can define your contract in your interfaces, and also you can inherit multiple interfaces on each class.

The interface would implement the methods, properties in the class, and then, you can customize their logic as needed. When you initialize the object with this interface, you'll be able to use the exposed properties or methods.

example :

```<code>public enum VehicleMake
{
    Acura,
    Audi,
    BMW,
    Chevrolet,
    Dodge,
    Fait,
    Ford,
    Hyundai,
    Honda,
    Nissan,
    Toyota
}

public enum FuelType
{
    Gas,
    Diesel
}

public interface IVehicle
{
    FuelType Fuel { get; }

    VehicleMake Make { get; set; }

    string Model { get; set; }

    int MakeYear { get; set; }

    IRental Rental { get; set; }
}

public interface IRental
{
    bool IsRented { get; set; }
}

public class Rental : IRental
{
    public bool IsRented { get; set; }
}

public class Car : IVehicle
{
    public FuelType Fuel => FuelType.Gas;

    public VehicleMake Make { get; set; }

    public string Model { get; set; }

    public int MakeYear { get; set; }

    public IRental Rental { get; set; }

}

public class Truck : IVehicle
{
    public FuelType Fuel => FuelType.Diesel;

    public VehicleMake Make { get; set; }

    public string Model { get; set; }

    public int MakeYear { get; set; }

    public IRental Rental { get; set; }

}
</code>```

This would give us this :

```<code>var vehicles = new List<IVehicle>
{
    new Car
    {
        Make = VehicleMake.BMW,
        MakeYear = 2020,
        Rental = new Rental { IsRented = true }
    },
    new Car
    {
        Make = VehicleMake.Toyota,
        MakeYear = 2000,
        Rental = new Rental { IsRented = false }
    },
    new Truck
    {
        Make = VehicleMake.Nissan,
        MakeYear = 2015,
        Rental = new Rental { IsRented = false }
    }
};

foreach (var vehicle in vehicles)
{
    Console.Write($"{vehicle.GetType().Name}\t");
    Console.Write($"{vehicle.Make.ToString()}\t");
    Console.Write($"{vehicle.MakeYear.ToString()}\t");
    Console.Write($"{vehicle.Fuel.ToString()}\t");

    if (vehicle.Rental?.IsRented == true)
    {
        Console.Write("rented");
    }
    else
    {
        Console.Write("not rented");
    }

    Console.WriteLine();
}
</code>```

So, any new vehicle type (such as Car, Truck, ..etc) it should implement IVehicle. The IRental interface I have put only one property as I don't know what you want to implement inside the actual class, likewise the other classes. but since you'll implement the concrete class, you should be able to determine the main properties and method that should be in the interface.

Body:
Imagine a rental company that has cars for the company to use internally and trucks to rent. The cars use gas and the trucks use diesel. The trucks have additional things that they do that cars do not - they are rented. So I have the following code:

abstract class Vehicle
{
    public abstract FuelType Fuel();
}

class Car : Vehicle
{
    public override FuelType Fuel()
    {
        return FuelType.Gas;
    }
}

class Truck : Vehicle
{
    public override FuelType Fuel()
    {
        return FuelType.Diesel;
    }

    //Not in base class or Car class
    public List<Rental> Rentals()
    {
        return new List<Rental>();
    }
}

class Rental
{
      //...some stuff here
}

enum FuelType
{
    Gas,
    Diesel
}

What is normally done when the child classes have additional methods and properties? Example:

        List<Vehicle> vehicles = new List<Vehicle>() { };

        vehicles.Add(new Car());
        vehicles.Add(new Truck());

        foreach (var vehicle in vehicles)
        {
            Console.WriteLine(vehicle.Fuel().ToString());

            //Pseudocode here:
            if(vehicle.GetType() is Truck)
            {
                //Provide rental information
                Truck truck = (Truck)vehicle;
                truck.ProvideSomeInfo();
            }
        }

I get how polymorphism works when you have classes that have all the same methods, properties, fields, etc. What is normally done when you need to work with the base class AND you need to work with additional methods, fields, properties that all the children do not share?

All the abstract tutorials that I have found just show the simpler case when all the children have the same sets of methods, properties, fields.

Body:
in your case, using interface would be more appropriate.

you can define your contract in your interfaces, and also you can inherit multiple interfaces on each class.

The interface would implement the methods, properties in the class, and then, you can customize their logic as needed. When you initialize the object with this interface, you'll be able to use the exposed properties or methods.

example :

public enum VehicleMake
{
    Acura,
    Audi,
    BMW,
    Chevrolet,
    Dodge,
    Fait,
    Ford,
    Hyundai,
    Honda,
    Nissan,
    Toyota
}

public enum FuelType
{
    Gas,
    Diesel
}

public interface IVehicle
{
    FuelType Fuel { get; }

    VehicleMake Make { get; set; }

    string Model { get; set; }

    int MakeYear { get; set; }

    IRental Rental { get; set; }
}

public interface IRental
{
    bool IsRented { get; set; }
}

public class Rental : IRental
{
    public bool IsRented { get; set; }
}

public class Car : IVehicle
{
    public FuelType Fuel => FuelType.Gas;

    public VehicleMake Make { get; set; }

    public string Model { get; set; }

    public int MakeYear { get; set; }

    public IRental Rental { get; set; }

}

public class Truck : IVehicle
{
    public FuelType Fuel => FuelType.Diesel;

    public VehicleMake Make { get; set; }

    public string Model { get; set; }

    public int MakeYear { get; set; }

    public IRental Rental { get; set; }

}

This would give us this :

var vehicles = new List<IVehicle>
{
    new Car
    {
        Make = VehicleMake.BMW,
        MakeYear = 2020,
        Rental = new Rental { IsRented = true }
    },
    new Car
    {
        Make = VehicleMake.Toyota,
        MakeYear = 2000,
        Rental = new Rental { IsRented = false }
    },
    new Truck
    {
        Make = VehicleMake.Nissan,
        MakeYear = 2015,
        Rental = new Rental { IsRented = false }
    }
};

foreach (var vehicle in vehicles)
{
    Console.Write($"{vehicle.GetType().Name}\t");
    Console.Write($"{vehicle.Make.ToString()}\t");
    Console.Write($"{vehicle.MakeYear.ToString()}\t");
    Console.Write($"{vehicle.Fuel.ToString()}\t");

    if (vehicle.Rental?.IsRented == true)
    {
        Console.Write("rented");
    }
    else
    {
        Console.Write("not rented");
    }

    Console.WriteLine();
}

So, any new vehicle type (such as Car, Truck, ..etc) it should implement IVehicle. The IRental interface I have put only one property as I don't know what you want to implement inside the actual class, likewise the other classes. but since you'll implement the concrete class, you should be able to determine the main properties and method that should be in the interface.


问:
NotImplementedError: bounds checking is not supported for CUDA
I'm trying to run code on my GPU, and firstly I clashed with the problem of having a working CUDA on ubuntu 18.04. After some pain I was suggested to work in a Docker Image, where I have (I presume) a well working CUDA version (I'm starting learning pytorch, and I was able to obtain a torch.cuda.is_available() = True).

After that I tried to run a simple code copied here, in order to see if effectively my GPU was able to do its job.

Unfortunately not... I receive the message:

```<code>NotImplementedError: bounds checking is not supported for CUDA
</code>```

and I really wasn't able to understand a proper way to fix it.

This is what I obtain if I run nvidia-smi

```<code>+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.33.01    Driver Version: 440.33.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce 940M        On   | 00000000:0A:00.0 Off |                  N/A |
| N/A   36C    P0    N/A /  N/A |    242MiB /  2004MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+
</code>```

And this is what I obtain if I run nvcc --version

```<code>nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Sun_Jul_28_19:07:16_PDT_2019
Cuda compilation tools, release 10.1, V10.1.243
</code>```

答:
Seems like the community is dealing with some bugs

So I tried some hacks and it actually worked!!!

Just changed the line

@jit(target ="cuda")

to

@jit

Body:
I'm trying to run code on my GPU, and firstly I clashed with the problem of having a working CUDA on ubuntu 18.04. After some pain I was suggested to work in a Docker Image, where I have (I presume) a well working CUDA version (I'm starting learning pytorch, and I was able to obtain a torch.cuda.is_available() = True).

After that I tried to run a simple code copied here, in order to see if effectively my GPU was able to do its job.

Unfortunately not... I receive the message:

NotImplementedError: bounds checking is not supported for CUDA

and I really wasn't able to understand a proper way to fix it.

This is what I obtain if I run nvidia-smi

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.33.01    Driver Version: 440.33.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce 940M        On   | 00000000:0A:00.0 Off |                  N/A |
| N/A   36C    P0    N/A /  N/A |    242MiB /  2004MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

And this is what I obtain if I run nvcc --version

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Sun_Jul_28_19:07:16_PDT_2019
Cuda compilation tools, release 10.1, V10.1.243


问:
Python - Array of Indexes of all appearances of a certain element in an array
This question is very similar to this question, Question, except for the fact that I need an answer for Python.

I'll explain the question anyway. If I have an array of characters, for example ["a", "b", "a", "c"], then it needs to return an array that includes the indexes of all the appearances of a certain character.

This means that if I input ['a', 'b', 'a', 'c', 'c', 'a'], and I need to find all appearances of 'a', then it would output [0, 2, 5].

I also need the program to be pretty fast, as I need to mass generate my final product, so the whole program needs to be quick. I will probably be running this piece of code millions of times in my code so the quicker it is the better, but I am accepting anything right now.

Right now my code does not work since it simply output [0, 0, 0] (I am running through a for loop so it isn't fast either)

Could someone please help? Thanks!

答:
A simple option, not optimised for speed:

list_of_characters = ['a', 'b', 'a', 'c', 'c', 'a']
character = 'a'
index_list = [i for i,v in enumerate(list_of_characters) if v == character]
```

Edit: If you're doing this calculation a lot and the list doesn't change between each run, you should pre-compute the solutions and store them in an easily accessible format.

Body:
A simple option, not optimised for speed:

list_of_characters = ['a', 'b', 'a', 'c', 'c', 'a']
character = 'a'
index_list = [i for i,v in enumerate(list_of_characters) if v == character]

Edit: If you're doing this calculation a lot and the list doesn't change between each run, you should pre-compute the solutions and store them in an easily accessible format.


问:
JPA table "sequence" does not exist
Database:

```<code>user_account
id(pk)
email
password
...

user_detail
id(pk fk)
name_first
name_last
...
</code>```

Entity

```<code>@Entity
@Table(name="user_account")
@SecondaryTable(name="user_detail", pkJoinColumns=@PrimaryKeyJoinColumn())
public class UserAccount implements Serializable{
    private static final long serialVersionUID = -2606506548742732094L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String email;
    private String password;
    private String tab;
    private String shortcut;
    private String setting;
    private Integer role;

    @Column(table="user_detail", name="name_first")
    private String nameFirst;
    @Column(table="user_detail", name="name_last")
    private String nameLast;
    @Column(table="user_detail")
    private String occupation;
    @Column(table="user_detail")
    @Temporal(TemporalType.DATE)
    private Date birth;
    ....
}
</code>```

Action

```<code>    try{
        EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        em.persist(currentUser);

        transaction.commit();
    } catch (Exception e){
    }
</code>```

Error

INFO: [EL Warning]: 2012-01-06
  18:45:46.77--ClientSession(17472935)--Exception [EclipseLink-4002]
  (Eclipse Persistence Services - 2.3.0.v20110604-r9504):
  org.eclipse.persistence.exceptions.DatabaseException Internal
  Exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Table
  'mazedb.sequence' doesn't exist Error Code: 1146 Call: UPDATE SEQUENCE
  SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?  bind => [2
  parameters bound] Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE
  SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")

INFO: ERROR:  Internal Exception:
  com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Table
  'mazedb.sequence' doesn't exist Error Code: 1146 Call: UPDATE SEQUENCE
  SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?  bind => [2
  parameters bound] Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE
  SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")

I tried the other way around, having two different entities merged by @PrimaryKeyJoinColumn but I got the same error.

答:
This exception can occur even if you use @GeneratedValue(strategy=GenerationType.IDENTITY)!

From the EclipseLink Wiki:

Note: IDENTITY strategy is database specific and not supported on all database. IDENTITY is supported on Sybase, DB2, SQL Server, MySQL, Derby, JavaDB, Informix, SQL Anywhere, H2, HSQL, Access, and Postgres databases.

I changed the database server and client from MySQL to MariaDB which is not supported for GenerationType.IDENTITY as stated above.
So I had to add the following property to the persistence.xml:

```<code><persistence ...
  <persistence-unit ...
  ...
  <properties>
    <property name="eclipselink.target-database" value="MySQL"/>
  </properties>
  ...
</code>```

Title: JPA table "sequence" does not exist

Body:
Database:

user_account
id(pk)
email
password
...

user_detail
id(pk fk)
name_first
name_last
...

Entity

@Entity
@Table(name="user_account")
@SecondaryTable(name="user_detail", pkJoinColumns=@PrimaryKeyJoinColumn())
public class UserAccount implements Serializable{
    private static final long serialVersionUID = -2606506548742732094L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String email;
    private String password;
    private String tab;
    private String shortcut;
    private String setting;
    private Integer role;

    @Column(table="user_detail", name="name_first")
    private String nameFirst;
    @Column(table="user_detail", name="name_last")
    private String nameLast;
    @Column(table="user_detail")
    private String occupation;
    @Column(table="user_detail")
    @Temporal(TemporalType.DATE)
    private Date birth;
    ....
}

Action

    try{
        EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        em.persist(currentUser);

        transaction.commit();
    } catch (Exception e){
    }

Error

INFO: [EL Warning]: 2012-01-06
  18:45:46.77--ClientSession(17472935)--Exception [EclipseLink-4002]
  (Eclipse Persistence Services - 2.3.0.v20110604-r9504):
  org.eclipse.persistence.exceptions.DatabaseException Internal
  Exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Table
  'mazedb.sequence' doesn't exist Error Code: 1146 Call: UPDATE SEQUENCE
  SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?  bind => [2
  parameters bound] Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE
  SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")

INFO: ERROR:  Internal Exception:
  com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Table
  'mazedb.sequence' doesn't exist Error Code: 1146 Call: UPDATE SEQUENCE
  SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?  bind => [2
  parameters bound] Query: DataModifyQuery(name="SEQUENCE" sql="UPDATE
  SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")

I tried the other way around, having two different entities merged by @PrimaryKeyJoinColumn but I got the same error.

Body:
This exception can occur even if you use @GeneratedValue(strategy=GenerationType.IDENTITY)!

From the EclipseLink Wiki:

Note: IDENTITY strategy is database specific and not supported on all database. IDENTITY is supported on Sybase, DB2, SQL Server, MySQL, Derby, JavaDB, Informix, SQL Anywhere, H2, HSQL, Access, and Postgres databases.

I changed the database server and client from MySQL to MariaDB which is not supported for GenerationType.IDENTITY as stated above.
So I had to add the following property to the persistence.xml:

<persistence ...
  <persistence-unit ...
  ...
  <properties>
    <property name="eclipselink.target-database" value="MySQL"/>
  </properties>
  ...


问:
Which of these lines is more efficient (CPU/memory-wise) when executed in jQuery?
I have two scenerios. In each scenerio, tell me which version of doing the same exact thing is more efficient (e.g. uses less CPU or memory):

First scenerio:

```<code>/*version 1*/
    $('body').append('#something');
/*version 2*/
    $('#something').insertAfter('body > *:last-child');
</code>```

Second scenerio:

```<code>/*version 1*/
    $('#something').method1();
    $('#something').method2();
    $('#something').method3();
/*version 2*/
    var $reference = $('#something');
    $reference.method1();
    $reference.method2();
    $reference.method3();
</code>```

So in each scenerio, which version is more efficient?

答:
```<code>$('#something').method1().method2().method3();
</code>```

unless you plan to reuse the object, then do

```<code>var $ref = $('#ref');
$ref.method1().method2().method3();
</code>```

Body:
I have two scenerios. In each scenerio, tell me which version of doing the same exact thing is more efficient (e.g. uses less CPU or memory):

First scenerio:

/*version 1*/
    $('body').append('#something');
/*version 2*/
    $('#something').insertAfter('body > *:last-child');

Second scenerio:

/*version 1*/
    $('#something').method1();
    $('#something').method2();
    $('#something').method3();
/*version 2*/
    var $reference = $('#something');
    $reference.method1();
    $reference.method2();
    $reference.method3();

So in each scenerio, which version is more efficient?

Body:
$('#something').method1().method2().method3();

unless you plan to reuse the object, then do

var $ref = $('#ref');
$ref.method1().method2().method3();


问:
For loop not showing correct count when outputting, showing up number too high in C++
I am having trouble showing up the correct count in my for loop. It works for my previous codes, but when I use this one, the count is too big. What I am trying to do in do to have my for loop count the inputed number and subtract the number each time it runs through. For example:

When I type in 50 using this code:

```<code>double change; //input variable for change
cin >> change;

//for loop for 50 dollar bills
for (int fif = change; fif >= 50; fif -=50)
{
 b++; //this is the count variable
 change = fif - 50;
}

if (b == 1)
cout << b << " $50 bill\n";
else
cout <<"";

cout << change; //output the change variable after loop
</code>```

The result will output:

```<code>1 50 dollar bill
0.00
</code>```

However when I change the numbers to match for $20 bills my code looks like this:

```<code>  //for loop for twenty dollar bills
 for (int twen = change; twen <= 40 && twen >=20 ; twen -=20)
{
 c++; //count variable
 change = twen - 20;
}

if (c == 1)
cout << c << " $20 dollar bill\n";
else if (c > 1)
cout << c << " $20 dollar bills\n";
else
cout << "";

cout << change;
</code>```

And the output number always changes for the count for the output. For example if I type in 40:

```<code>32661 $20 dollar bills
0.00
</code>```

Any idea on what I'm doing wrong?

答: It seems like your counting variable is not initialized. Variables can start existence from 0 by luck (good or bad luck, depending on your attitude). Or they can start from a seemingly random value. In any case, you cannot depend on the initial value of int variables.

Body:
I am having trouble showing up the correct count in my for loop. It works for my previous codes, but when I use this one, the count is too big. What I am trying to do in do to have my for loop count the inputed number and subtract the number each time it runs through. For example:

When I type in 50 using this code:

double change; //input variable for change
cin >> change;

//for loop for 50 dollar bills
for (int fif = change; fif >= 50; fif -=50)
{
 b++; //this is the count variable
 change = fif - 50;
}

if (b == 1)
cout << b << " $50 bill\n";
else
cout <<"";

cout << change; //output the change variable after loop

The result will output:

1 50 dollar bill
0.00

However when I change the numbers to match for $20 bills my code looks like this:

  //for loop for twenty dollar bills
 for (int twen = change; twen <= 40 && twen >=20 ; twen -=20)
{
 c++; //count variable
 change = twen - 20;
}

if (c == 1)
cout << c << " $20 dollar bill\n";
else if (c > 1)
cout << c << " $20 dollar bills\n";
else
cout << "";

cout << change;

And the output number always changes for the count for the output. For example if I type in 40:

32661 $20 dollar bills
0.00

Any idea on what I'm doing wrong?


问:
How to create a percentage tracker that doesn't slow down the program significantly
I have a question regarding percentage trackers. I have a percentage tracker for a generation tool, and the percentage tracker significantly slows it down. (5 secs vs 35 secs)

```<code>def wiiu():
    time.sleep(0.2)
    track = 100000
    os.remove("Codes.txt")
    file = open("Codes.txt","w")
    clear()
    print("3ds and Wii-U Friend Code Generator")
    print("")
    print("How many codes to generate: ")
    amt = int(input())
    print("Generating...")
    total = 0
    total1 = 0
    file = open("codes.txt","w")
    while total < amt:
        pc = 200/(int(amt)+(int(total)))
        total1 + 1
        pc1 = pc + 100
        fcpt1 = str(randint(1000, 9999)) + "-" + str(randint(1000, 9999)) + "-" + str(randint(1000,9999))
        total = total+1
        ctypes.windll.kernel32.SetConsoleTitleW("Friend Code Generator - " + str(round(total*pc)) + "% completed")
        if total == track:
            print(str(total) + " generated.")
            track = track + 100000
        file.write(str(fcpt1)+"\n")
    clear()
    file.close()
    if total == 1:
        print("Completed! Generated "+ str(total) +" code!")
    else:
        print("Completed! Generated "+ str(total) +" codes!")
    ctypes.windll.kernel32.SetConsoleTitleW("Friend Code Generator - 2.0.4")
    a = input("Press enter to close! Thanks for using!")
    close()
</code>```

Any help is much appreciated!

答:
Without proper profiling I can only guess but probably ctypes.windll.kernel32.SetConsoleTitleW takes some time especially when running it every iteration. Maybe just doing it every 100th time makes it faster?

```<code>while total < amt:
        pc = 200/(int(amt)+(int(total)))
        total1 + 1
        pc1 = pc + 100
        fcpt1 = str(randint(1000, 9999)) + "-" + str(randint(1000, 9999)) + "-" + str(randint(1000,9999))
        total = total+1

        # Use the modulo operator to let it run every 100th time
        if total % 100 == 0:
            ctypes.windll.kernel32.SetConsoleTitleW("Friend Code Generator - " + str(round(total*pc)) + "% completed")
        if total == track:
            print(str(total) + " generated.")
            track = track + 100000
        file.write(str(fcpt1)+"\n")
</code>```

Body:
I have a question regarding percentage trackers. I have a percentage tracker for a generation tool, and the percentage tracker significantly slows it down. (5 secs vs 35 secs)

def wiiu():
    time.sleep(0.2)
    track = 100000
    os.remove("Codes.txt")
    file = open("Codes.txt","w")
    clear()
    print("3ds and Wii-U Friend Code Generator")
    print("")
    print("How many codes to generate: ")
    amt = int(input())
    print("Generating...")
    total = 0
    total1 = 0
    file = open("codes.txt","w")
    while total < amt:
        pc = 200/(int(amt)+(int(total)))
        total1 + 1
        pc1 = pc + 100
        fcpt1 = str(randint(1000, 9999)) + "-" + str(randint(1000, 9999)) + "-" + str(randint(1000,9999))
        total = total+1
        ctypes.windll.kernel32.SetConsoleTitleW("Friend Code Generator - " + str(round(total*pc)) + "% completed")
        if total == track:
            print(str(total) + " generated.")
            track = track + 100000
        file.write(str(fcpt1)+"\n")
    clear()
    file.close()
    if total == 1:
        print("Completed! Generated "+ str(total) +" code!")
    else:
        print("Completed! Generated "+ str(total) +" codes!")
    ctypes.windll.kernel32.SetConsoleTitleW("Friend Code Generator - 2.0.4")
    a = input("Press enter to close! Thanks for using!")
    close()

Any help is much appreciated!

Body:
Without proper profiling I can only guess but probably ctypes.windll.kernel32.SetConsoleTitleW takes some time especially when running it every iteration. Maybe just doing it every 100th time makes it faster?

while total < amt:
        pc = 200/(int(amt)+(int(total)))
        total1 + 1
        pc1 = pc + 100
        fcpt1 = str(randint(1000, 9999)) + "-" + str(randint(1000, 9999)) + "-" + str(randint(1000,9999))
        total = total+1

        # Use the modulo operator to let it run every 100th time
        if total % 100 == 0:
            ctypes.windll.kernel32.SetConsoleTitleW("Friend Code Generator - " + str(round(total*pc)) + "% completed")
        if total == track:
            print(str(total) + " generated.")
            track = track + 100000
        file.write(str(fcpt1)+"\n")