Skip to content

Commit 4372fc3

Browse files
committed
[1986] Make ServiceMethod fail if parameters don't match arity
Bug: #1986 Signed-off-by: Gwendal Daniel <[email protected]>
1 parent 8978a9c commit 4372fc3

File tree

3 files changed

+87
-13
lines changed

3 files changed

+87
-13
lines changed

CHANGELOG.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ Publishing a project that contains representations now produces libraries that a
5454
- https://github.com/eclipse-syson/syson/issues/1970[#1970] [export] Implement textual export of `AllocationUsage` and `AllocationDefinition`.
5555
- https://github.com/eclipse-syson/syson/issues/1948[#1948] [diagrams] Add _New Satisfy_ tool on `RequirementUsage` graphical nodes. This tool allows to create a `SatisfyRequirementUsage` on the selected `RequirementUsage`.
5656
Also add a _New Satisfy Requirement_ graphical edge tool between `Feature` graphical nodes and `RequirementUsage` graphical nodes.
57+
- https://github.com/eclipse-syson/syson/issues/1986[#1986] [services] Make `ServiceMethod#aql` and `ServiceMethod#aqlSelf` throw an exception if the provided parameters don't match the service method arity.
58+
As a result, the application won't start if a service call is constructed with an invalid number of arguments.
5759

5860
=== New features
5961

backend/services/syson-services/src/main/java/org/eclipse/syson/util/ServiceMethod.java

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2025 Obeo.
2+
* Copyright (c) 2025, 2026 Obeo.
33
* This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v2.0
55
* which accompanies this distribution, and is available at
@@ -16,6 +16,7 @@
1616
import java.lang.invoke.SerializedLambda;
1717
import java.lang.reflect.InvocationTargetException;
1818
import java.lang.reflect.Method;
19+
import java.text.MessageFormat;
1920
import java.util.Arrays;
2021

2122
/**
@@ -81,8 +82,11 @@ public final class ServiceMethod {
8182

8283
private final String name;
8384

84-
private ServiceMethod(String name) {
85+
private final int arity;
86+
87+
private ServiceMethod(String name, int arity) {
8588
this.name = name;
89+
this.arity = arity;
8690
}
8791

8892
/**
@@ -105,6 +109,7 @@ public String name() {
105109
* @return A full AQL expression string
106110
*/
107111
public String aqlSelf(String... params) {
112+
this.checkArity(params);
108113
if (params == null || params.length == 0) {
109114
return AQLUtils.getSelfServiceCallExpression(this.name);
110115
}
@@ -128,6 +133,7 @@ public String aql(String var, String... params) {
128133
if (var == null || var.isEmpty()) {
129134
throw new IllegalArgumentException("var must be a non empty AQL variable name");
130135
} else {
136+
this.checkArity(params);
131137
if (params == null || params.length == 0) {
132138
aqlString = AQLUtils.getServiceCallExpression(var, this.name);
133139
}
@@ -143,49 +149,49 @@ public String aql(String var, String... params) {
143149
* Instance method with signature {@code R method(T self)}.
144150
*/
145151
public static <S, T> ServiceMethod of0(Inst0<S, T> ref) {
146-
return new ServiceMethod(methodName(ref));
152+
return new ServiceMethod(methodName(ref), 0);
147153
}
148154

149155
/**
150156
* Instance method with signature {@code R method(T self, P1 p1)}.
151157
*/
152158
public static <S, T, P1> ServiceMethod of1(Inst1<S, T, P1> ref) {
153-
return new ServiceMethod(methodName(ref));
159+
return new ServiceMethod(methodName(ref), 1);
154160
}
155161

156162
/**
157163
* Instance method with signature {@code R method(T self, P1 p1, P2 p2)}.
158164
*/
159165
public static <S, T, P1, P2> ServiceMethod of2(Inst2<S, T, P1, P2> ref) {
160-
return new ServiceMethod(methodName(ref));
166+
return new ServiceMethod(methodName(ref), 2);
161167
}
162168

163169
/**
164170
* Instance method with signature {@code R method(T self, P1 p1, P2 p2, P3 p3)}.
165171
*/
166172
public static <S, T, P1, P2, P3> ServiceMethod of3(Inst3<S, T, P1, P2, P3> ref) {
167-
return new ServiceMethod(methodName(ref));
173+
return new ServiceMethod(methodName(ref), 3);
168174
}
169175

170176
/**
171177
* Instance method with signature {@code R method(T self, P1 p1, P2 p2, P3 p3, P4 p4)}.
172178
*/
173179
public static <S, T, P1, P2, P3, P4> ServiceMethod of4(Inst4<S, T, P1, P2, P3, P4> ref) {
174-
return new ServiceMethod(methodName(ref));
180+
return new ServiceMethod(methodName(ref), 4);
175181
}
176182

177183
/**
178184
* Instance method with signature {@code R method(T self, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)}.
179185
*/
180186
public static <S, T, P1, P2, P3, P4, P5> ServiceMethod of5(Inst5<S, T, P1, P2, P3, P4, P5> ref) {
181-
return new ServiceMethod(methodName(ref));
187+
return new ServiceMethod(methodName(ref), 5);
182188
}
183189

184190
/**
185191
* Instance method with signature {@code R method(T self, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)}.
186192
*/
187193
public static <S, T, P1, P2, P3, P4, P5, P6> ServiceMethod of6(Inst6<S, T, P1, P2, P3, P4, P5, P6> ref) {
188-
return new ServiceMethod(methodName(ref));
194+
return new ServiceMethod(methodName(ref), 6);
189195
}
190196

191197
// ---------------------- Factories for static methods ----------------------
@@ -194,28 +200,28 @@ public static <S, T, P1, P2, P3, P4, P5, P6> ServiceMethod of6(Inst6<S, T, P1, P
194200
* Static method with signature {@code R method(T self)}.
195201
*/
196202
public static <T> ServiceMethod ofStatic0(IStat0<T> ref) {
197-
return new ServiceMethod(methodName(ref));
203+
return new ServiceMethod(methodName(ref), 0);
198204
}
199205

200206
/**
201207
* Static method with signature {@code R method(T self, P1 p1)}.
202208
*/
203209
public static <T, P1> ServiceMethod ofStatic1(IStat1<T, P1> ref) {
204-
return new ServiceMethod(methodName(ref));
210+
return new ServiceMethod(methodName(ref), 1);
205211
}
206212

207213
/**
208214
* Static method with signature {@code R method(T self, P1 p1, P2 p2)}.
209215
*/
210216
public static <T, P1, P2> ServiceMethod ofStatic2(IStat2<T, P1, P2> ref) {
211-
return new ServiceMethod(methodName(ref));
217+
return new ServiceMethod(methodName(ref), 2);
212218
}
213219

214220
/**
215221
* Static method with signature {@code R method(T self, P1 p1, P2 p2, P3 p3)}.
216222
*/
217223
public static <T, P1, P2, P3> ServiceMethod ofStatic3(IStat3<T, P1, P2, P3> ref) {
218-
return new ServiceMethod(methodName(ref));
224+
return new ServiceMethod(methodName(ref), 3);
219225
}
220226

221227
// ---------------------- SAMs for method references ----------------------
@@ -431,5 +437,24 @@ private static String methodName(Serializable lambdaRef) {
431437
throw new IllegalStateException("Cannot resolve method name from lambda", e);
432438
}
433439
}
440+
441+
/**
442+
* Checks that the provided {@code params} array matches the arity of the service method.
443+
*
444+
* @param params the parameters passed to the service method (excluding self)
445+
*
446+
* @throws IllegalArgumentException if the provided {@code params} doesn't match the arity of the service method.
447+
*/
448+
private void checkArity(String... params) {
449+
int paramLength;
450+
if (params == null) {
451+
paramLength = 0;
452+
} else {
453+
paramLength = params.length;
454+
}
455+
if (this.arity != paramLength) {
456+
throw new IllegalArgumentException(MessageFormat.format("Service {0} has an arity of {1} but {2} parameters were provided", this.name, this.arity, paramLength));
457+
}
458+
}
434459
}
435460

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 Obeo.
3+
* This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v2.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Obeo - initial API and implementation
12+
*******************************************************************************/
13+
package org.eclipse.syson.util;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
17+
18+
import org.junit.jupiter.api.DisplayName;
19+
import org.junit.jupiter.api.Test;
20+
21+
/**
22+
* ServiceMethod-related tests.
23+
*
24+
* @author gdaniel
25+
*/
26+
public class ServiceMethodTest {
27+
28+
@Test
29+
@DisplayName("GIVEN a service method with arity 0, WHEN an AQL expression is constructed with 0 parameter, THEN the expression is returned")
30+
public void givenServiceMethodWithArity0WhenAQLExpressionIsConstructedWith0ParameterThenExpressionIsReturned() {
31+
String expression = ServiceMethod.of0(ServiceMethodTest::serviceWithArity0).aqlSelf();
32+
assertThat(expression).isEqualTo("aql:self.serviceWithArity0()");
33+
expression = ServiceMethod.of0(ServiceMethodTest::serviceWithArity0).aql("var");
34+
assertThat(expression).isEqualTo("aql:var.serviceWithArity0()");
35+
}
36+
37+
@Test
38+
@DisplayName("GIVEN a service method with arity 0, WHEN an AQL expression is constructed with 1 parameter, THEN an exception is thrown")
39+
public void givenServiceMethodWithArity0WhenAQLExpressionIsConstructedWith1ParameterThenExceptionIsThrown() {
40+
assertThatThrownBy(() -> ServiceMethod.of0(ServiceMethodTest::serviceWithArity0).aqlSelf("param1")).isInstanceOf(IllegalArgumentException.class);
41+
assertThatThrownBy(() -> ServiceMethod.of0(ServiceMethodTest::serviceWithArity0).aql("var", "param1")).isInstanceOf(IllegalArgumentException.class);
42+
}
43+
44+
private Object serviceWithArity0(Object self) {
45+
return null;
46+
}
47+
}

0 commit comments

Comments
 (0)