cobigen icon indicating copy to clipboard operation
cobigen copied to clipboard

CobiGen CLI does not generate properly from non-build Java sources

Open EduardKrieger opened this issue 2 years ago • 2 comments

Expected behavior

As a CobiGen CLI user, I want to be able to generate from non-build Java sources. The bug from the following issue #1497 will be split and tracked here.

Actual behavior

The CobiGen CLI is not able to generate all the Java files from non-build Java source files.

Steps to reproduce

  1. Install devonfw-ide and CobiGen CLI
  2. Create a devon4j Java project (devon java create com.example.application.cobigenexample)
  3. Create a package and an entity class package com.example.application.cobigenexample.customermanagement.dataaccess.api
package com.example.application.cobigenexample.customermanagement.dataaccess.api;

import java.sql.Timestamp;

import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "Customer")
public class CustomerEntity {

  private String firstname;

  private String lastname;

  private int age;

  /**
   * @return the firstname
   */
  public String getFirstname() {
    return firstname;
  }

  /**
   * @param firstname the firstname to set
   */
  public void setFirstname(String firstname) {
    this.firstname = firstname;
  }

  /**
   * @return the lastname
   */
  public String getLastname() {
    return lastname;
  }

  /**
   * @param lastname the lastname to set
   */
  public void setLastname(String lastname) {
    this.lastname = lastname;
  }

  /**
   * @return the age
   */
  public int getAge() {
    return age;
  }

  /**
   * @param age the age to set
   */
  public void setAge(int age) {
    this.age = age;
  }

}
  1. Run Cobigen: devon cobigen generate core/src/main/java/com/example/application/cobigenexample/customermanagement/dataaccess/api/CustomerEntity.java Select 1,3,5,6,8 as increments

The following error occurs:

[DEBUG] While reading the input core\src\main\java\com\example\application\cobigenexample\customermanagement\dataaccess\api\CustomerEntity.java with the inputreader com.devonfw.cobigen.javaplugin.JavaTriggerInterpreter@72c8e7b, an exception occured. Trying next input reader...
com.devonfw.cobigen.api.exception.CobiGenRuntimeException: Compiled class com.example.application.cobigenexample.customermanagement.dataaccess.api.CustomerEntity has not been found. Most probably you need to build project core.
        at com.devonfw.cobigen.javaplugin.inputreader.JavaParserUtil.getJavaContext(JavaParserUtil.java:145)
        at com.devonfw.cobigen.javaplugin.inputreader.JavaInputReader.createParsedClassLoader(JavaInputReader.java:452)
        at com.devonfw.cobigen.javaplugin.inputreader.JavaInputReader.read(JavaInputReader.java:395)
        at com.devonfw.cobigen.impl.generator.InputInterpreterImpl.readInput(InputInterpreterImpl.java:96)
        at com.devonfw.cobigen.impl.generator.InputInterpreterImpl.read(InputInterpreterImpl.java:70)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at com.devonfw.cobigen.api.util.ExceptionUtil.invokeTarget(ExceptionUtil.java:76)
        at com.devonfw.cobigen.impl.aop.CachedInterceptor.invoke(CachedInterceptor.java:41)
        at com.sun.proxy.$Proxy14.read(Unknown Source)
        at com.devonfw.cobigen.impl.generator.CobiGenImpl.read(CobiGenImpl.java:170)
        at com.devonfw.cobigen.cli.commands.GenerateCommand.preprocess(GenerateCommand.java:187)
        at com.devonfw.cobigen.cli.commands.GenerateCommand.doAction(GenerateCommand.java:115)
        at com.devonfw.cobigen.cli.commands.CommandCommons.call(CommandCommons.java:36)
        at com.devonfw.cobigen.cli.commands.CommandCommons.call(CommandCommons.java:15)
        at picocli.CommandLine.executeUserObject(CommandLine.java:1953)
        at picocli.CommandLine.access$1300(CommandLine.java:145)
        at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)
        at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
        at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)
        at picocli.CommandLine.execute(CommandLine.java:2078)
        at com.devonfw.cobigen.cli.CobiGenCLI.main(CobiGenCLI.java:37)
Caused by: java.lang.ClassNotFoundException: com.example.application.cobigenexample.customermanagement.dataaccess.api.CustomerEntity
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        at com.devonfw.cobigen.javaplugin.inputreader.JavaParserUtil.getJavaContext(JavaParserUtil.java:141)
        ... 25 common frames omitted
[ERROR] Invalid input for CobiGen, please check your input file 'core\src\main\java\com\example\application\cobigenexample\customermanagement\dataaccess\api\CustomerEntity.java'
[ERROR] There are no common Templates/Increments which could be generated from every of your inputs. Please think about executing generation one by one input file.
←[31m←[1mjava.util.InputMismatchException: No compatible input files.←[21m←[39m←[0m
←[3m    at com.devonfw.cobigen.cli.commands.GenerateCommand.preprocess(GenerateCommand.java:212)←[23m←[0m
←[3m    at com.devonfw.cobigen.cli.commands.GenerateCommand.doAction(GenerateCommand.java:115)←[23m←[0m
←[3m    at com.devonfw.cobigen.cli.commands.CommandCommons.call(CommandCommons.java:36)←[23m←[0m
←[3m    at com.devonfw.cobigen.cli.commands.CommandCommons.call(CommandCommons.java:15)←[23m←[0m
←[3m    at picocli.CommandLine.executeUserObject(CommandLine.java:1953)←[23m←[0m
←[3m    at picocli.CommandLine.access$1300(CommandLine.java:145)←[23m←[0m
←[3m    at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)←[23m←[0m
←[3m    at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)←[23m←[0m
←[3m    at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)←[23m←[0m
←[3m    at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)←[23m←[0m
←[3m    at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)←[23m←[0m
←[3m    at picocli.CommandLine.execute(CommandLine.java:2078)←[23m←[0m
←[3m    at com.devonfw.cobigen.cli.CobiGenCLI.main(CobiGenCLI.java:37)←[23m←[0m
[INFO ] Failed

After building the project (devon mvn clean install -Dmaven.test.skip=true) this error does not happen

Related/Dependent Issues

#1497

Comments/Hints:

Build a test case which implements the steps 1-4 and analyze and debug the error at com.devonfw.cobigen.javaplugin.inputreader.JavaParserUtil.getJavaContext(JavaParserUtil.java:145)

Affected version:

  • OS: Windows/Linux/Mac?
  • Browser: Chrome/Firefox/Safari?

EduardKrieger avatar Oct 18 '22 12:10 EduardKrieger

This issue stems from getContext() in the JavaParserUtil as it tries to load a corresponding .class for the given Java file, if the class is not found a CobigenRuntimeException is thrown.

In an attempt to circumvent the error and ignore the classloader, trying to work only with .java source files the Freemarker template engine fails as the templates expect a classObject to pass to the JavaUtil to access the Java reflection api, since the .class has not been loaded the Class<?> pojo passed to the JavaUtil is null and the program fails.

This issue is connected to #1594 because if an outdated .class file is loaded (in the case of the issue, a file with new fields) and the reflection API tries to access the added fields/methods from the source file in the loaded class it will fail as it can't find them. Outdated .class files will still work as long as the generation targets don't access the new fields (for example the CRUD rest service won't fail as it doesn't access new fields/methods in the class, but the Eto generation will!).

There are two possible solutions:

  1. notify the user to rebuild the project as it's being done already.
  2. work on new templates that work with the HashMaps derived from the .java source files without support of the Java reflection api (dangerous).

Reproduce:

  • to reproduce the CobigenRuntimeException due to the .class file not being found just delete the 'target' folder containing the compiled .class files
  • to correctly generate code with outdated .class files just select CRUD as increment after having added fields to the class
  • to fail an increment due to outdated .class files try generating ETOs after having added fields to the class

Lur1an avatar Oct 27 '22 09:10 Lur1an

@maybeec @hohwille maybe you got any suggestions for us? Would it suffice to prompt the user to re-build his project like before or should we adjust the templates like @Lur1an has mentioned?

jan-vcapgemini avatar Oct 28 '22 08:10 jan-vcapgemini