Skip to content

Commit b5d747d

Browse files
committed
Add assertion to verify Hibernate vs. our ANTLR versions.
See #3262
1 parent e1ef583 commit b5d747d

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
20+
import java.util.regex.Matcher;
21+
import java.util.regex.Pattern;
22+
23+
import org.antlr.v4.runtime.RuntimeMetaData;
24+
import org.hibernate.grammars.hql.HqlParser;
25+
import org.junit.jupiter.api.Test;
26+
27+
import org.springframework.asm.ClassReader;
28+
import org.springframework.asm.ClassVisitor;
29+
import org.springframework.asm.MethodVisitor;
30+
import org.springframework.asm.Opcodes;
31+
import org.springframework.lang.Nullable;
32+
33+
/**
34+
* Test to verify that we use the same Antlr version as Hibernate. We parse {@code org.hibernate.grammars.hql.HqlParser}
35+
* byte code to extract the constant that represents the Antlr version.
36+
* <p>
37+
* If this test fails, we should check and upgrade the Antlr version in our project.
38+
*
39+
* @author Mark Paluch
40+
*/
41+
class AntlrVersionTests {
42+
43+
@Test
44+
void antlrVersionConvergence() throws Exception {
45+
46+
ClassReader reader = new ClassReader(HqlParser.class.getName());
47+
ExpectedAntlrVersionVisitor visitor = new ExpectedAntlrVersionVisitor();
48+
reader.accept(visitor, 0);
49+
50+
String expectedVersion = visitor.getExpectedVersion();
51+
String description = String.format("ANTLR version '%s' expected by Hibernate while our ANTLR version '%s'",
52+
expectedVersion, RuntimeMetaData.VERSION);
53+
54+
assertThat(expectedVersion).isNotNull();
55+
assertThat(RuntimeMetaData.VERSION) //
56+
.describedAs(description) //
57+
.isEqualTo(expectedVersion);
58+
}
59+
60+
private static class ExpectedAntlrVersionVisitor extends ClassVisitor {
61+
62+
private static final Pattern versionPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+");
63+
private static final int API = Opcodes.ASM10_EXPERIMENTAL;
64+
65+
private @Nullable String expectedVersion;
66+
67+
ExpectedAntlrVersionVisitor() {
68+
super(API);
69+
}
70+
71+
@Nullable
72+
String getExpectedVersion() {
73+
return expectedVersion;
74+
}
75+
76+
@Override
77+
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
78+
String[] exceptions) {
79+
80+
// static block
81+
if (!name.equals("<clinit>")) {
82+
return null;
83+
}
84+
85+
return new MethodVisitor(API) {
86+
87+
/**
88+
* Intercept Load constant. First one is the generating version, second is the compile version.
89+
*/
90+
@Override
91+
public void visitLdcInsn(Object value) {
92+
93+
if (value instanceof String && expectedVersion == null) {
94+
95+
Matcher matcher = versionPattern.matcher(value.toString());
96+
if (matcher.matches()) {
97+
expectedVersion = value.toString();
98+
}
99+
}
100+
super.visitLdcInsn(value);
101+
}
102+
};
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)