-
Notifications
You must be signed in to change notification settings - Fork 300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arch Unit configuration with lombok [Error] #337
Comments
As ArchUnit is (currently) built solely on byte code, there is unfortunately no way to check whether a class is annotated with an annoation with So from ArchUnit's (current) point of view, it doesn't matter how your bytecode is generated. I understand that you may still want to avoid the dependency on lombok; so maybe there is another signature in the generated bytecode that you can look for?
we can have a look at the bytecode together.) |
The imports
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.domain.SourceCodeLocation;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import java.util.List;
import static com.google.common.collect.FluentIterable.concat;
import static com.google.common.collect.Sets.newHashSet; static final ArchCondition<JavaClass> seemToContainGeneratedCode =
new ArchCondition<JavaClass>("seem to contain generated code") {
@Override
public void check(JavaClass javaClass, ConditionEvents events) {
List<SourceCodeLocation> locations = concat(
javaClass.tryGetMethod("equals", Object.class).asSet(),
javaClass.tryGetMethod("hashCode").asSet(),
javaClass.tryGetMethod("toString").asSet()
).transform(JavaMethod::getSourceCodeLocation).toList();
boolean allMethodsDefinedInSameLine =
locations.size() == 3 && newHashSet(locations).size() == 1;
events.add(new SimpleConditionEvent(javaClass, allMethodsDefinedInSameLine, String.format(
"%s has equals(Object), hashCode() and toString() defined in the same line %s",
javaClass.getName(), locations.get(0)
)));
}
}; However, it turns out that for As you have already decompiled the example byte code: Could you copy and paste this decompiled code in a new Java source file, compile it and disassemble the new class file (using |
Didn't we look into that and couldn't find a solution in the past? 🤔 #75 |
…odeLocation #344 So far, the `sourceCodeLocation` of `JavaMember`s does not contain a line number, as it cannot reliably be inferred from the byte code (cf. #75). However, if the class file contains a [`LineNumberTable`](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.12) for a method, using the smallest line number from the `LineNumberTable` for the member's `sourceCodeLocation` – even if this probably corresponds to the first executable statement and not to the method header definition – seems to be more useful to me than using the fallback line number `0` in any case. So for example, I would infer the line number `10` from the following byte code: ``` void methodWithBodyStartingInLine10(); descriptor: ()V flags: (0x0000) Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: bipush 10 5: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 11: bipush 11 13: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 16: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 19: bipush 12 21: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 24: return LineNumberTable: line 10: 0 line 11: 8 line 12: 16 line 13: 24 ``` (My example's method header is actually defined in line 9, but I prefer 10 as opposed to 0... 😉) Note that I do even get a line number for an empty method from the following byte code: ``` void emptyMethodDefinedInLine15(); descriptor: ()V flags: (0x0000) Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 15: 0 ``` Even if line numbers inferred in this way do not exactly point to the method header definition, they can be used to compare different methods (i.e., the ordering should be correct). This would allow for new rules like, for example (irrespective of whether I'd personally want to have them as arch rules or not): * Public methods are defined _before_ private methods. * `equals`, `hashCode` and `toString` are not generated by a framework (or a developer... 🙈) in the _same_ line (cf. #337) With this pull request, line numbers are recorded for `JavaCodeUnit`s (`JavaMethod`s, `JavaConstructor`s, `JavaStaticInitializer`s) if the class file has a `LineNumberTable`. (The reported line number `0` for `JavaField`s is unchanged, as it cannot be inferred from byte code.)
Hello everyone. I know you have a possible solution to this problem, but I don't understand or don't know how to solve it. |
The So yes, when your class is modified, the line numbers may change, but that shouldn't affect the condition. I've maybe tried too hard to keep the code for the condition short, so it's probably not obvious... 😉 TL;DR: I believe that with the next release of ArchUnit, you can use the code above to detect classes that most likely use generated |
Ok, i will try this solution and tell you how it went. |
Right! That's why I wrote:
|
Ok ok ok, agreed |
@JaimLus, did you already have a chance to try the suggestion from #337 (comment) with ArchUnit 0.14.1? |
I have not really tried what the comment says with the new version of arch unit. I think that we close the issue, and if when testing does not work, there we see if the case is reopened or a new one is created. |
All right, so be it. 👍 Thank you! |
…odeLocation #344 So far, the `sourceCodeLocation` of `JavaMember`s does not contain a line number, as it cannot reliably be inferred from the byte code (cf. #75). However, if the class file contains a [`LineNumberTable`](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.12) for a method, using the smallest line number from the `LineNumberTable` for the member's `sourceCodeLocation` – even if this probably corresponds to the first executable statement and not to the method header definition – seems to be more useful to me than using the fallback line number `0` in any case. So for example, I would infer the line number `10` from the following byte code: ``` void methodWithBodyStartingInLine10(); descriptor: ()V flags: (0x0000) Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: bipush 10 5: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 11: bipush 11 13: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 16: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 19: bipush 12 21: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 24: return LineNumberTable: line 10: 0 line 11: 8 line 12: 16 line 13: 24 ``` (My example's method header is actually defined in line 9, but I prefer 10 as opposed to 0... 😉) Note that I do even get a line number for an empty method from the following byte code: ``` void emptyMethodDefinedInLine15(); descriptor: ()V flags: (0x0000) Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 15: 0 ``` Even if line numbers inferred in this way do not exactly point to the method header definition, they can be used to compare different methods (i.e., the ordering should be correct). This would allow for new rules like, for example (irrespective of whether I'd personally want to have them as arch rules or not): * Public methods are defined _before_ private methods. * `equals`, `hashCode` and `toString` are not generated by a framework (or a developer... 🙈) in the _same_ line (cf. #337) With this pull request, line numbers are recorded for `JavaCodeUnit`s (`JavaMethod`s, `JavaConstructor`s, `JavaStaticInitializer`s) if the class file has a `LineNumberTable`. (The reported line number `0` for `JavaField`s is unchanged, as it cannot be inferred from byte code.)
Hi everyone,
I need help setting up the arch unit with lombok.
I am testing that my domain models are not annotated with @DaTa from lombok library, but I run the test and I get this error:
What recommendation do you suggest?
This is test:
The text was updated successfully, but these errors were encountered: