faktor-ips

faktor ips cannot find product component class


I want to make a project with Faktor IPS which is both a model project and a product deffinition project. And I want to and a UI using Linkki. Here is my project structure:

Project structure (Stack overflow won't let me add images, I hope the link works)

In the src/main/java folder are the classes to make the linkki UI and the .model.hausrat is the package where faktor ips generated the code for the policy components.

The policy components and product components are in the faktorips-repository-toc.xml in the folder src/main/resources under rg/linkki_framework/fips/Hausrat_linkki_app/model/internal/faktorips-repository-toc.xml

And this is what it looks like:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<FaktorIps-TableOfContents productDataVersion="0.0.1" xmlversion="3.0">
 <ProductComponent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.deckungen.Fahrraddiebstahl___2022__01" ipsObjectId="beispiel.Fahrraddiebstahl 2022-01" ipsObjectQualifiedName="deckungen.Fahrraddiebstahl 2022-01" kindId="beispiel.Fahrraddiebstahl" versionId="2022-01" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/deckungen/Fahrraddiebstahl 2022-01.xml"/>
 <ProductComponent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratGrunddeckungstyp" ipsObjectId="beispiel.HRD-Kompakt 2022-01" ipsObjectQualifiedName="deckungen.HRD-Kompakt 2022-01" kindId="beispiel.HRD-Kompakt" versionId="2022-01" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/deckungen/HRD-Kompakt 2022-01.xml"/>
 <ProductComponent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratGrunddeckungstyp" ipsObjectId="beispiel.HRD-Optimal 2022-01" ipsObjectQualifiedName="deckungen.HRD-Optimal 2022-01" kindId="beispiel.HRD-Optimal" versionId="2022-01" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/deckungen/HRD-Optimal 2022-01.xml"/>
 <ProductComponent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.deckungen.Ueberspannung___2022__01" ipsObjectId="beispiel.Ueberspannung 2022-01" ipsObjectQualifiedName="deckungen.Ueberspannung 2022-01" kindId="beispiel.Ueberspannung" versionId="2022-01" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/deckungen/Ueberspannung 2022-01.xml"/>
 <PolicyCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Deckung" ipsObjectId="hasurat.Deckung" ipsObjectQualifiedName="hasurat.Deckung"/>
 <ProductCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Deckungstyp" ipsObjectId="hasurat.Deckungstyp" ipsObjectQualifiedName="hasurat.Deckungstyp"/>
 <PolicyCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratGrunddeckung" ipsObjectId="hasurat.HausratGrunddeckung" ipsObjectQualifiedName="hasurat.HausratGrunddeckung"/>
 <ProductCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratGrunddeckungstyp" ipsObjectId="hasurat.HausratGrunddeckungstyp" ipsObjectQualifiedName="hasurat.HausratGrunddeckungstyp"/>
 <ProductCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratProdukt" ipsObjectId="hasurat.HausratProdukt" ipsObjectQualifiedName="hasurat.HausratProdukt"/>
 <PolicyCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratVertrag" ipsObjectId="hasurat.HausratVertrag" ipsObjectQualifiedName="hasurat.HausratVertrag"/>
 <PolicyCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratZusatzdekung" ipsObjectId="hasurat.HausratZusatzdekung" ipsObjectQualifiedName="hasurat.HausratZusatzdekung"/>
 <ProductCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratZusatzdekungstyp" ipsObjectId="hasurat.HausratZusatzdekungstyp" ipsObjectQualifiedName="hasurat.HausratZusatzdekungstyp"/>
 <ProductCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Produkt" ipsObjectId="hasurat.Produkt" ipsObjectQualifiedName="hasurat.Produkt"/>
 <PolicyCmptType implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Vertrag" ipsObjectId="hasurat.Vertrag" ipsObjectQualifiedName="hasurat.Vertrag"/>
 <EnumContent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Zahlweise" ipsObjectId="modell.hasurat.Zahlweise" ipsObjectQualifiedName="hasurat.Zahlweise.Type"/>
 <ProductComponent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratProdukt" ipsObjectId="beispiel.HR-Kompakt 2022-01" ipsObjectQualifiedName="produkt.HR-Kompakt 2022-01" kindId="beispiel.HR-Kompakt" versionId="2022-01" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/produkt/HR-Kompakt 2022-01.xml"/>
 <ProductComponent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.HausratProdukt" ipsObjectId="beispiel.HR-Optimal 2022-01" ipsObjectQualifiedName="produkt.HR-Optimal 2022-01" kindId="beispiel.HR-Optimal" versionId="2022-01" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/produkt/HR-Optimal 2022-01.xml"/>
 <TableContent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Tariftabelle" ipsObjectId="tabellen.Tariftabelle Kompakt" ipsObjectQualifiedName="tabellen.Tariftabelle Kompakt" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/tabellen/Tariftabelle Kompakt.xml"/>
 <TableContent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Tariftabelle" ipsObjectId="tabellen.Tariftabelle Optimal" ipsObjectQualifiedName="tabellen.Tariftabelle Optimal" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/tabellen/Tariftabelle Optimal.xml"/>
 <TableContent implementationClass="org.linkki_framework.fips.Hausrat_linkki_app.model.hasurat.Tarifzonentabelle" ipsObjectId="tabellen.Tarifzonentabelle" ipsObjectQualifiedName="tabellen.Tarifzonentabelle" xmlResource="org/linkki_framework/fips/Hausrat_linkki_app/model/tabellen/Tarifzonentabelle.xml"/>
</FaktorIps-TableOfContents>

At one point I try to get a list of all product components that are instances of the HausratProdukt. like this:

private final List<HausratProdukt> produkte;
private IRuntimeRepository repository;

this.repository = PolicyRuntimeRepositoryLookup.getInstance().getRuntimeRepository();
this.produkte = repository.getAllProductComponents(HausratProdukt.class);

The class PolicyRuntimeRepositoryLookup looks like this:

public class PolicyRuntimeRepositoryLookup implements IRuntimeRepositoryLookup {

    private static final long serialVersionUID = 1L;

    private static final PolicyRuntimeRepositoryLookup SINGLETON = new PolicyRuntimeRepositoryLookup();

    private static final String TOC_PATH = "org/linkki_framework/fips/Hausrat_linkki_app/model/internal/faktorips-repository-toc.xml";
                                        //"de/faktorzehn/ipm/core/model/internal/faktorips-repository-toc.xml";

    private transient IRuntimeRepository runtimeRepository;

    private PolicyRuntimeRepositoryLookup() {
        runtimeRepository = ClassloaderRuntimeRepository.create(TOC_PATH);
    }

    public static PolicyRuntimeRepositoryLookup getInstance() {
        return SINGLETON;
    }

    @Override
    public IRuntimeRepository getRuntimeRepository() {
        return runtimeRepository;
    }

    private Object readResolve() {
        return SINGLETON;
    }
}

It crashes at the line:

this.produkte = repository.getAllProductComponents(HausratProdukt.class);

With the following error:

java.lang.RuntimeException: Can't load class org.linkki_framework.fips.Hausrat_linkki_app.model.deckungen.Ueberspannung___2022__01
    at org.faktorips.runtime.internal.AbstractTocBasedRuntimeRepository.getClass(AbstractTocBasedRuntimeRepository.java:272)
    at org.faktorips.runtime.internal.AbstractClassLoadingRuntimeRepository.getAllProductComponentsInternal(AbstractClassLoadingRuntimeRepository.java:329)
    at org.faktorips.runtime.internal.AbstractRuntimeRepository.getAllProductComponents(AbstractRuntimeRepository.java:265)
    at org.linkki_framework.fips.Hausrat_linkki_app.pmo.AngebotSectionPmo.<init>(AngebotSectionPmo.java:44)
    at org.linkki_framework.fips.Hausrat_linkki_app.page.AngebotPage.createContent(AngebotPage.java:37)
    at org.linkki_framework.fips.Hausrat_linkki_app.view.AngebotView.enter(AngebotView.java:47)
    at com.vaadin.navigator.Navigator.performNavigateTo(Navigator.java:778)
    at com.vaadin.navigator.Navigator.lambda$navigateTo$9a874efd$1(Navigator.java:702)
    at com.vaadin.navigator.ViewBeforeLeaveEvent.navigate(ViewBeforeLeaveEvent.java:54)
    at com.vaadin.navigator.View.beforeLeave(View.java:79)
    at com.vaadin.navigator.Navigator.runAfterLeaveConfirmation(Navigator.java:730)
    at com.vaadin.navigator.Navigator.navigateTo(Navigator.java:701)
    at com.vaadin.navigator.Navigator.navigateTo(Navigator.java:678)
    at org.linkki_framework.fips.Hausrat_linkki_app.menu.AngebotMenuItem.lambda$0(AngebotMenuItem.java:27)
    at com.vaadin.ui.MenuBar.changeVariables(MenuBar.java:210)
    at com.vaadin.server.communication.ServerRpcHandler.changeVariables(ServerRpcHandler.java:616)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:468)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:411)
    at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:275)
    at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:91)
    at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
    at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1637)
    at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:464)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.ClassNotFoundException: org.linkki_framework.fips.Hausrat_linkki_app.model.deckungen.Ueberspannung___2022__01
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:168)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at org.faktorips.runtime.internal.AbstractTocBasedRuntimeRepository.getClass(AbstractTocBasedRuntimeRepository.java:269)
    ... 60 more

I noticed that the faktorips-repository-toc.xml saves product components with an implementationClass of whatever Policy class they are a an instance of.

For example beispiel.HRD-Kompakt 2022-1 has an implementationClass of ...hasurat.HausratGrunddeckungstyp, but those product components that are actually instances of Zusatzdeckungstyp are saved in the toc.xml file with their actual name in the implementationClass.

For example ...deckungen.Ueberspannung___2022__01 instead of ...hasurat.HausratZusatzdekungstyp, which I would actually expect.

I have no idea why it saves only these differently, or how to change it, since this is a built in component of faktor ips.

Maybe the builtin method repository.getAllProductComponents(...) searches for classes in the src/main/java folder (where all the other classes are) and doesn't find these specific ones, which are in the src/main/resources folder?

But this too is automatically generated and I don't know how to change it. Of course I could manually move the classes into the src/main/java folder, but that would kind of defeat the purpose of it being automatically generated. Can anyone help?


Solution

  • The reason for the specific implementation classes is that you use formulas in those products. When using formulas with Faktor-IPS, there are two options:

    1. Generating and compiling Java code for them
    2. Generating Java code inside their XML files and interpreting it with a Groovy formula evaluator at runtime

    You can choose, which option you use in a project in the 'Faktor-IPS Code Generator Settings' (rightclick on the project -> properties -> 'Faktor-IPS Code Generator Settings' or in the XML of the .ipsproject file). The property 'Formula Compiling' can be set to 'Subclass' for the first or 'XML' for the second option. The default value 'Both' generates table-of-contents-entries and Java classes like the first option and additionally Java code in the XMLs like the second.

    When using Maven for your project, you need to adapt to the variant you choose. With variant 1, you need to make sure that Java files in src/main/resources are also compiled as described in https://www.faktorzehn.org/dokumentation/verwendung-von-faktor-ips-projekten-als-maven-dependencies/ :

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <executions>
            <execution>
                <id>add-source</id>
                <phase>generate-sources</phase>
                <goals><goal>add-source</goal></goals>
                <configuration>
                    <sources>
                        <source>${project.basedir}/derived</source>
                    </sources>
                </configuration>
            </execution>
        </executions>
    </plugin>
    

    If you choose the second option, you need to add a dependency to https://mvnrepository.com/artifact/org.faktorips/faktorips-runtime-groovy and add the formula evaluator to your repository with

    repository.setFormulaEvaluatorFactory(new GroovyFormulaEvaluatorFactory());