Skip to content

Commit

Permalink
Merge pull request #43121 from MaryamZi/fix-object-type-annotations
Browse files Browse the repository at this point in the history
Fix method annotations for object types
  • Loading branch information
MaryamZi committed Jul 26, 2024
2 parents d7e4f3e + 48033c1 commit abf6c71
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.ballerina.runtime.api.types.ResourceMethodType;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.utils.StringUtils;
import io.ballerina.runtime.api.utils.TypeUtils;
import io.ballerina.runtime.api.values.BString;
import io.ballerina.runtime.internal.scheduling.Strand;
import io.ballerina.runtime.internal.types.BAnnotatableType;
Expand Down Expand Up @@ -58,7 +59,13 @@ public static void processAnnotations(MapValue globalAnnotMap, Type bType) {
type.setAnnotations((MapValue<BString, Object>) globalAnnotMap.get(annotationKey));
}

if (type.getTag() != TypeTags.OBJECT_TYPE_TAG && type.getTag() != TypeTags.SERVICE_TAG) {
if (type.getTag() == TypeTags.TYPE_REFERENCED_TYPE_TAG) {
Type impliedType = TypeUtils.getImpliedType(type);
if (isNonObjectType(impliedType.getTag())) {
return;
}
type = (BAnnotatableType) impliedType;
} else if (isNonObjectType(type.getTag())) {
return;
}
BObjectType objectType = (BObjectType) type;
Expand All @@ -75,6 +82,10 @@ public static void processAnnotations(MapValue globalAnnotMap, Type bType) {
}
}

private static boolean isNonObjectType(int impliedTypeTag) {
return impliedTypeTag != TypeTags.OBJECT_TYPE_TAG && impliedTypeTag != TypeTags.SERVICE_TAG;
}

private static void setMethodAnnotations(MapValue<BString, Object> globalAnnotMap, BString annotationKey,
BMethodType resourceMethod) {
if (globalAnnotMap.containsKey(annotationKey)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public static BValue getResourceAnnotation(BString methodName, ArrayValue path,
return null;
}

private static String generateMethodName(BString methodName, ArrayValue path) {
public static String generateMethodName(BString methodName, ArrayValue path) {
StringBuilder funcName = new StringBuilder();
funcName.append("$").append(methodName.getValue());
for (int i = 0; i < path.size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,22 @@

import io.ballerina.runtime.api.TypeTags;
import io.ballerina.runtime.api.types.AnnotatableType;
import io.ballerina.runtime.api.types.MethodType;
import io.ballerina.runtime.api.types.ObjectType;
import io.ballerina.runtime.api.types.RemoteMethodType;
import io.ballerina.runtime.api.types.ResourceMethodType;
import io.ballerina.runtime.api.types.ServiceType;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.utils.StringUtils;
import io.ballerina.runtime.api.utils.TypeUtils;
import io.ballerina.runtime.api.values.BString;
import io.ballerina.runtime.api.values.BTypedesc;
import io.ballerina.runtime.internal.TypeChecker;
import io.ballerina.runtime.internal.values.ArrayValue;
import io.ballerina.runtime.internal.values.MapValueImpl;
import io.ballerina.runtime.internal.values.TupleValueImpl;
import io.ballerina.runtime.internal.values.TypedescValue;
import org.ballerinalang.nativeimpl.jvm.servicetests.ServiceValue;
import org.ballerinalang.test.BCompileUtil;
import org.ballerinalang.test.BRunUtil;
import org.ballerinalang.test.CompileResult;
Expand Down Expand Up @@ -221,9 +231,57 @@ public void testConstTypeAnnotAccess() {
BRunUtil.invoke(resultOne, "testConstTypeAnnotAccess");
}

@Test
public void testObjectTypeAnnotations() {
BRunUtil.invoke(resultOne, "testObjectTypeAnnotations");
}

@Test
public void testServiceObjectTypeAnnotations() {
BRunUtil.invoke(resultOne, "testServiceObjectTypeAnnotations");
}

@AfterClass
public void tearDown() {
resultOne = null;
resultAccessNegative = null;
}

public static Object getMethodAnnotations(BTypedesc bTypedesc, BString method, BString annotName) {
Type describingType = TypeUtils.getImpliedType(bTypedesc.getDescribingType());
int tag = describingType.getTag();
assert tag == TypeTags.OBJECT_TYPE_TAG || tag == TypeTags.SERVICE_TAG;

ObjectType objectType = (ObjectType) describingType;
String methodName = method.getValue();
for (MethodType methodType : objectType.getMethods()) {
if (methodType.getName().equals(methodName)) {
return methodType.getAnnotation(annotName);
}
}
return null;
}

public static Object getRemoteMethodAnnotations(BTypedesc bTypedesc, BString method, BString annotName) {
String methodName = method.getValue();
for (RemoteMethodType methodType :
((ServiceType) TypeUtils.getImpliedType(bTypedesc.getDescribingType())).getRemoteMethods()) {
if (methodType.getName().equals(methodName)) {
return methodType.getAnnotation(annotName);
}
}
return null;
}

public static Object getResourceMethodAnnotations(BTypedesc bTypedesc, BString method, ArrayValue path,
BString annotName) {
String methodName = ServiceValue.generateMethodName(method, path);
for (ResourceMethodType methodType :
((ServiceType) TypeUtils.getImpliedType(bTypedesc.getDescribingType())).getResourceMethods()) {
if (methodType.getName().equals(methodName)) {
return methodType.getAnnotation(annotName);
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// specific language governing permissions and limitations
// under the License.

import ballerina/jballerina.java;

type Annot record {
string foo;
int bar?;
Expand Down Expand Up @@ -429,6 +431,135 @@ function testListExprInConstAnnot() {
assertEquality(["key1", "key2"], config.key);
}

annotation record {| string name; |} ObjectAnnot on type;
annotation MethodAnnot on function;

@ObjectAnnot {
name: "ObjectTypeWithAnnots"
}
type ObjectTypeWithAnnots object {
@MethodAnnot
function getInt() returns int;
};

type ObjectTypeWithoutAnnots object {
function getInt() returns int;
};

function testObjectTypeAnnotations() {
record {|string name;|}? objectAnnot = ObjectTypeWithAnnots.@ObjectAnnot;
assertTrue(objectAnnot !is ());
record {|string name;|} objectAnnotValue = <record {|string name;|}> objectAnnot;
assertEquality("ObjectTypeWithAnnots", objectAnnotValue.name);

anydata methodAnnot = getMethodAnnotations(ObjectTypeWithAnnots, "getInt", "MethodAnnot");
assertTrue(methodAnnot);

record {|string name;|}? objectAnnot2 = ObjectTypeWithoutAnnots.@ObjectAnnot;
assertTrue(objectAnnot2 is ());

anydata methodAnnot2 = getMethodAnnotations(ObjectTypeWithoutAnnots, "getInt", "MethodAnnot");
assertTrue(methodAnnot2 is ());
}

annotation ServiceTypeAnnot on type, class;
annotation Kind ServiceTypeMethodAnnot on function;

@ServiceTypeAnnot
public type S1 service object {

@ServiceTypeMethodAnnot {
kind: "resource"
}
resource function get res() returns string;

@ServiceTypeMethodAnnot {
kind: "remote"
}
remote function rem() returns string;

@ServiceTypeMethodAnnot {
kind: "normal"
}
function fn() returns int;

resource function get res2() returns string;
};

public type S2 service object {

resource function get res() returns string;

remote function rem() returns string;

function fn() returns int;

@ServiceTypeMethodAnnot {
kind: "remote 2"
}
remote function rem2() returns string;
};

type Kind record {|
string kind;
|};

function testServiceObjectTypeAnnotations() {
true? serviceObjectAnnot = S1.@ServiceTypeAnnot;
assertTrue(serviceObjectAnnot);

anydata methodAnnot = getResourceMethodAnnotations(S1, "get", ["res"], "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is Kind);
Kind kind = <Kind> methodAnnot;
assertEquality("resource", kind.kind);

methodAnnot = getRemoteMethodAnnotations(S1, "rem", "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is Kind);
kind = <Kind> methodAnnot;
assertEquality("remote", kind.kind);

methodAnnot = getMethodAnnotations(S1, "fn", "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is Kind);
kind = <Kind> methodAnnot;
assertEquality("normal", kind.kind);

methodAnnot = getResourceMethodAnnotations(S1, "get", ["res2"], "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is ());

serviceObjectAnnot = S2.@ServiceTypeAnnot;
assertTrue(serviceObjectAnnot is ());

methodAnnot = getResourceMethodAnnotations(S2, "get", ["res"], "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is ());

methodAnnot = getRemoteMethodAnnotations(S2, "rem", "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is ());

methodAnnot = getMethodAnnotations(S2, "fn", "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is ());

methodAnnot = getRemoteMethodAnnotations(S2, "rem2", "ServiceTypeMethodAnnot");
assertTrue(methodAnnot is Kind);
kind = <Kind> methodAnnot;
assertEquality("remote 2", kind.kind);
}

function getMethodAnnotations(typedesc<object {}> bTypedesc, string method, string annotName) returns anydata =
@java:Method {
'class: "org/ballerinalang/test/annotations/AnnotationRuntimeTest"
} external;

function getRemoteMethodAnnotations(typedesc<service object {}> bTypedesc, string method, string annotName) returns anydata =
@java:Method {
'class: "org/ballerinalang/test/annotations/AnnotationRuntimeTest"
} external;

function getResourceMethodAnnotations(typedesc<service object {}> bTypedesc, string method,
string[] path, string annotName) returns anydata =
@java:Method {
'class: "org/ballerinalang/test/annotations/AnnotationRuntimeTest"
} external;

function assertTrue(anydata actual) {
assertEquality(true, actual);
}
Expand Down

0 comments on commit abf6c71

Please sign in to comment.