ArchUnit icon indicating copy to clipboard operation
ArchUnit copied to clipboard

Rule to restrict to specific bytecode java version

Open pjroth opened this issue 3 years ago • 7 comments

Hi, I can't seem to determine how to accomplish my use case. Any help would be greatly appreciated.

Is it possible to verify that a jar I create is compiled to java 8 or below including all dependencies used by that jar?

I don't see anything in the API to check for bytecode version but I might just be missing it.

Thank you, Peter

pjroth avatar Sep 10 '20 16:09 pjroth

Unfortunately this is not possible at the moment, because nobody ever had a use case for it :thinking: It is easily possible to read the byte code version of the imported class AFAIS, but so far the info is simply ignored. What I don't understand is your point "including all dependencies", because either these dependencies are themselves "objects under test" and directly inspected by an ArchRule, or they are external, but then it does not really make sense to test them, since in any other scenario they could be swapped out against versions that have a different bytecode version. Or am I understanding this wrongly?

codecholeric avatar Sep 26 '20 18:09 codecholeric

It is easily possible to read the byte code version of the imported class Is it possible using the current API or possible that it could be added?

Regarding the dependencies I agree these could be swapped out by clients. But i can’t control that of course. What i would like to do is protect myself from adding a dependency to my project that doesn’t meet the minimum bytecode requirement my project has.

To give more background. I have an SDK that is used to access one of our REST APIs. That SDK has a requirement for java 7 or lower. I just had a bug in this project however because I updated a dependency version to the latest version. This is our usual process to update dependencies when working on a project. However, many java libraries do not make it easy to determine the bytecode they are compiled to. So i inadvertently added a dependency that uses java 8 when the previous version was java 7 even though I looked at the docs, I didn’t look hard enough though. This then broke one of the clients (in another project at the same company) that uses this SDK.

I would love to write a test to protect myself from this. I fully understand this only will work if the project using my SDK doesn’t change this dependency version but we can’t solve all the problems. Although maybe I could shade to avoid this. That can be a discussion for another day perhaps. :)

Thanks for the response. Have a great day!

pjroth avatar Sep 26 '20 22:09 pjroth

Would running your test suite with a JRE 7 catch such bugs?

hankem avatar Sep 27 '20 10:09 hankem

I also feel like the only way to really be sure it works with JRE 7 is to test it with JRE 7 :thinking: That's by the way also what ArchUnit does itself :wink: Because sometimes even though the bytecode would be compatible there still is some incompatibility in implementation/behavior...

codecholeric avatar Sep 27 '20 12:09 codecholeric

I think running the tests with JRE 7 would catch these types of bugs for sure. What i don’t prefer though is now the developer and CI environment setups get more complex. It is becoming harder and harder to even get old JREs. I was hoping for a solution that allows me to install one JDK. Now with java 9+ and the ‘release’ flag it makes compiling to older versions much easier and less error prone. At the moment I install only java 11 but i can compile all the way back to 7.

All this has made me wonder why the maven coordinates don’t support an option for specifying the bytecode version. 🤔 Although I believe that multi-version jars are a newish thing too when using java modules.

pjroth avatar Sep 27 '20 12:09 pjroth

So is there anything you could imagine adding to ArchUnit to help with my use case or do we just say I should really be testing with the target JRE I require? From my perspective, I would much prefer to just add a simple test case rather than configuring multiple JREs for tests (which is far more complex). But I understand if this use case is perhaps outside the goals of ArchUnit.

pjroth avatar Sep 29 '20 13:09 pjroth

I could well imagine to add this to ArchUnit (to know which version of byte code was imported seems to be just fair, if we also have things like the respective source file or even an MD5 sum of the imported class if activated). My personal problem is, that I don't have the capacity at the moment to implement it. If you (or anybody else) would want to give it a shot to create a PR, I'm more than happy to support you / merge it!

The entry point would be

com.tngtech.archunit.core.importer.JavaClassProcessor.visit(int version, ...) {...}

And in fact AFAIS this first parameter version is exactly the bytecode version (even though there seems to be some caveat that major and minor version are encoded together into this integer :thinking: So it might be sth. like version & 0x0000FFFF and version & 0xFFFF0000 to parse major and minor version, see Javadoc). It should be simply adding this as property to JavaClassBuilder and that's it :thinking: Maybe it would be nice to have a JavaClassVersion where you could ask for classVersion.getByteCodeMajorVersion() and classVersion.getJavaVersion() to easier map sth. like 51 to Java 7 :thinking: Anyway, the mapping can e.g. be found in https://fabianlee.org/2018/01/19/java-determining-the-java-version-used-to-compile-a-class-class-file-has-the-wrong-version/ (don't know if there is any highly official source :wink:). I'm really sorry that I can't do it myself at the moment, but I really want to push for the Generics support with all the (very limited) capacity I have at the moment! :disappointed:

codecholeric avatar Sep 29 '20 22:09 codecholeric