[QFJ-987] JPMS: Change field classes generation to resolve split package issue Created: 23/Sep/19  Updated: 05/Jun/20

Status: In Progress
Project: QuickFIX/J
Component/s: Message Generation
Affects Version/s: 2.1.1
Fix Version/s: None

Type: Improvement Priority: Default
Reporter: Vlad Mureșan Assignee: Vlad Mureșan
Resolution: Unresolved Votes: 0
Labels: Message, QuickfixJ

Issue Links:
Duplicate
is duplicated by QFJ-985 Java Modules Closed

 Description   

The new module system available since JDK 9 does not allow duplicate packages on the module path.
As a result an application that depends on more than one messages version will have a split package issue, since quickfix.field exists in all quickfixj-messages-<version> jars.

The packaging needs to be changed in order to avoid duplicate packages used by different quickfixj modules.



 Comments   
Comment by Vlad Mureșan [ 23/Sep/19 ]

I analysed a little bit the situation and I see the following potential solutions:

  1. Generate a quickfixj-fields jar to be used as dependency by the other messages jars. This way the jar can be imported only once and split package issue is avoided.
    Advantage: avoid code duplication, avoid split package issue
  2. Generate  quickfix.<version>.fields packages instead of quickfix.fields. This means that each quickfixj-messages-<version> jar will have its own fields package and the component should make sure to consume the fields from its corresponding package.
    Disadvantage: the common fields between FIX versions will be generated once for each messages version jar, so there is some code duplication. However, this means that the messages between versions are completely decoupled between FIX versions.
    I don't know if this solution is feasible, since the impact is quite big (this won't be backward compatible for client applications already using the quickfix.fields package). As a workaround for this a quickfix.fields package can be generated in the messages-all jar.

I would go for first solution to also keep the impact as low as possible and avoid code duplication. What do you think?
Please let me know if you have other preferences. I'll wait for your feedback before doing any actual changes.

Cheers,
Vlad

Comment by Gili [ 24/Sep/19 ]

Hi Vlad,

I'm just an end-user. You discuss possible solutions, but can you explain outline the existing situation? I understand that modules cannot import the same package from multiple sources but it's not clear to me why the existing design exports the same packages/classes from multiple JARs. Can you please break that down? It would help us understand the proposed solutions and maybe even come up with others. Thank you.

Comment by Christoph John [ 25/Sep/19 ]

Hi Gili,

I have to admit that I don't recall exactly why the module structure was done this way. Maybe it was the easiest way at that time when we migrated the modules from Ant to Maven or to OSGi.

Cheers,
Chris.

Comment by Marcin L [ 02/Apr/20 ]

This is a tough one.

1) creating a separate module for fields

Seems like relatively easy solution, but I don't think there is much benefit of doing this one as the core structure problem remains. This might be only feasible to get JPMS working. BTW. Do you have a branch version (or module descriptors) of what you were trying to do?

2) each message module should has it's own version of fields

I agree with you. Even though this might be a duplication of fields I think this is the right way as this decouples fields for each version of FIX dictionaries.

  • fields are different (some are missing, some are added)
  • enum values for certain fields are different (mostly added as FIX version increases, but possibly they can be removed)

PROBLEM

quickfix-core code already depends on classes from quickfix.field package. Moreover, the code base is dependent (need to be available at run-time) on fields from different FIX versions all together e.g. SessionRejectReason (added in 4.2). They are somewhat "protected" by the code to use them only when specific FIX version is used - still they all need to be in class path at run-time.

This is the reason why code generator plugin generates fields in a very specific order as the code generator plugin does not override field classes that have been created. Currently this super set is assembled into each Maven module quickfixj-messages-fix**, so even if an application is dependent on quickfixj-messages-fix40 it will contain fields from different FIX versions such as SessionRejectReason, otherwise things will fail at run-time e.g.

quickfix.Message#parseBody
throw new FieldException(SessionRejectReason.TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER, field.getTag());

I don't see an easy way of splitting this, but probably a way to go would be to abandon anaemic domain model and message modules would need to contain logic, so quickfix-core would delegate the logic depending on which version of FIX is being used. Also unit tests in quickfix-core are heavy dependent on fields and messages from different FIX versions.

Comment by Grigor Iliev [ 05/Jun/20 ]

I ran into same issue while trying to launch app from IDE. I was able to workaround it using the following maven configuration:

<dependency>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-all</artifactId>
<version>2.1.1</version>
<exclusions>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-messages-all</artifactId>
</exclusion>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-codegenerator</artifactId>
</exclusion>
<exclusion>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-dictgenerator</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.1.3</version>
</dependency>

Note that quickfixj-all/pom.xml uses maven-shade-plugin to copy everything from quickfixj-core, quickfixj-messages-all, quickfixj-codegenerator and quickfixj-dictgenerator to single fat jar. Thus, dependencies to these jars are not need. Maybe quickfixj-all/pom.xml should be updated to use optional dependencies instead? I.e.

<dependency>
<groupId>org.quickfixj</groupId>
<artifactId>quickfixj-core</artifactId>
<version>$

{project.version}

</version>
<optional>true</optional>
</dependency>

But in this case transitive dependencies should be explicitly specified in quickfixj-all/pom.xml. I.e.

<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.1.3</version>
</dependency>

If quickfixj-all/pom.xml is updated in this way, the aforementioned workaround won't be needed.

Generated at Tue May 14 21:32:41 UTC 2024 using JIRA 7.5.2#75007-sha1:9f5725bb824792b3230a5d8716f0c13e296a3cae.