Skip to content

Commit b4c8390

Browse files
authored
Merge pull request github#18137 from owen-mc/java/jax-rs-annotation-inheritance
Java: Update JAX-RS annotation inheritance
2 parents 531e637 + 19df33f commit b4c8390

File tree

10 files changed

+663
-12
lines changed

10 files changed

+663
-12
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* We now allow classes which don't have any JAX-RS annotations to inherit JAX-RS annotations from superclasses or interfaces. This is not allowed in the JAX-RS specification, but some implementations, like Apache CXF, allow it. This may lead to more alerts being found.

java/ql/lib/semmle/code/java/frameworks/JaxWS.qll

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,21 @@ private predicate hasPathAnnotation(Annotatable annotatable) {
147147
)
148148
}
149149

150+
/**
151+
* Holds if the class has or inherits the JaxRs `@Path` annotation.
152+
*/
153+
private predicate hasOrInheritsPathAnnotation(Class c) {
154+
hasPathAnnotation(c)
155+
or
156+
// Note that by the JAX-RS spec, JAX-RS annotations on classes and interfaces
157+
// are not inherited, but some implementations, like Apache CXF, do inherit
158+
// them. I think this only applies if there are no JaxRS annotations on the
159+
// class itself, as that is the rule in the JAX-RS spec for method
160+
// annotations.
161+
hasPathAnnotation(c.getAnAncestor()) and
162+
not exists(c.getAnAnnotation().(JaxRSAnnotation))
163+
}
164+
150165
/**
151166
* A method which is annotated with one or more JaxRS resource type annotations e.g. `@GET`, `@POST` etc.
152167
*/
@@ -191,7 +206,7 @@ class JaxRsResourceMethod extends Method {
191206
class JaxRsResourceClass extends Class {
192207
JaxRsResourceClass() {
193208
// A root resource class has a @Path annotation on the class.
194-
hasPathAnnotation(this)
209+
hasOrInheritsPathAnnotation(this)
195210
or
196211
// A sub-resource
197212
exists(JaxRsResourceClass resourceClass, Method method |
@@ -227,7 +242,7 @@ class JaxRsResourceClass extends Class {
227242
/**
228243
* Holds if this class is a "root resource" class
229244
*/
230-
predicate isRootResource() { hasPathAnnotation(this) }
245+
predicate isRootResource() { hasOrInheritsPathAnnotation(this) }
231246

232247
/**
233248
* Gets a `Constructor` that may be called by a JaxRS container to construct this class reflectively.

java/ql/test/library-tests/frameworks/JaxWs/JakartaRs1.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ class NotAResourceClass1Jakarta {
156156
class NotAResourceClass2Jakarta {
157157
}
158158

159-
class ExtendsJakartaRs1 extends JakartaRs1 {
159+
class ExtendsJakartaRs1 extends JakartaRs1 { // $ RootResourceClass
160160
@Override
161161
int Get() { // $ ResourceMethod
162162
return 1;
163163
}
164-
164+
165165
@Override
166166
@QueryParam("") // $ InjectionAnnotation
167167
void Post() {
@@ -189,12 +189,12 @@ void Head() {
189189
}
190190

191191
@Produces(MediaType.TEXT_XML) // $ ProducesAnnotation=text/xml
192-
class ExtendsJakartaRs1WithProducesAnnotation extends JakartaRs1 {
192+
class ExtendsJakartaRs1WithProducesAnnotation extends JakartaRs1 { // Not a root resource class because it has a JAX-RS annotation
193193
@Override
194194
int Get() { // $ ResourceMethod=text/xml
195195
return 2;
196196
}
197-
197+
198198
@Override
199199
@QueryParam("") // $ InjectionAnnotation
200200
void Post() {
@@ -212,4 +212,4 @@ void Put() { // $ ResourceMethod=text/html
212212
@Override
213213
void Options() { // $ ResourceMethod=text/xml
214214
}
215-
}
215+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import java.io.InputStream;
2+
import java.io.IOException;
3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.Type;
5+
import jakarta.ws.rs.GET;
6+
import jakarta.ws.rs.POST;
7+
import jakarta.ws.rs.DELETE;
8+
import jakarta.ws.rs.PUT;
9+
import jakarta.ws.rs.OPTIONS;
10+
import jakarta.ws.rs.HEAD;
11+
import jakarta.ws.rs.Path;
12+
import jakarta.ws.rs.BeanParam;
13+
import jakarta.ws.rs.CookieParam;
14+
import jakarta.ws.rs.FormParam;
15+
import jakarta.ws.rs.HeaderParam;
16+
import jakarta.ws.rs.MatrixParam;
17+
import jakarta.ws.rs.PathParam;
18+
import jakarta.ws.rs.Produces;
19+
import jakarta.ws.rs.QueryParam;
20+
import jakarta.ws.rs.client.Client;
21+
import jakarta.ws.rs.core.Context;
22+
import jakarta.ws.rs.core.MediaType;
23+
import jakarta.ws.rs.core.MultivaluedMap;
24+
import jakarta.ws.rs.core.Response;
25+
import jakarta.ws.rs.ext.MessageBodyReader;
26+
27+
class ExtendsJakartaRs3 extends JakartaRs3 { // $ RootResourceClass
28+
@Override
29+
public int Get() { // $ ResourceMethod
30+
return 1;
31+
}
32+
33+
@Override
34+
public @QueryParam("") // $ InjectionAnnotation
35+
void Post() {
36+
}
37+
38+
@Override
39+
public double Delete() { // $ ResourceMethod=application/json
40+
return 1.0;
41+
}
42+
43+
@Override
44+
public void Put() { // $ ResourceMethod=text/html
45+
}
46+
47+
@Produces("application/json") // $ ProducesAnnotation=application/json
48+
@Override
49+
public void Options() { // not a resource method because it has a jax-rs annotation, so it doesn't inherit any jax-rs annotations
50+
}
51+
52+
@Produces(MediaType.TEXT_XML) // $ ProducesAnnotation=text/xml
53+
@Override
54+
public void Head() { // not a resource method because it has a jax-rs annotation, so it doesn't inherit any jax-rs annotations
55+
}
56+
57+
}
58+
59+
@Produces(MediaType.TEXT_XML) // $ ProducesAnnotation=text/xml
60+
class ExtendsJakartaRs3WithProducesAnnotation extends JakartaRs3 { // Not a root resource class because it has a JAX-RS annotation
61+
@Override
62+
public int Get() { // $ ResourceMethod=text/xml
63+
return 2;
64+
}
65+
66+
@Override
67+
public @QueryParam("") // $ InjectionAnnotation
68+
void Post() {
69+
}
70+
71+
@Override
72+
public double Delete() { // $ ResourceMethod=application/json
73+
return 2.0;
74+
}
75+
76+
@Override
77+
public void Put() { // $ ResourceMethod=text/html
78+
}
79+
80+
@Override
81+
public void Options() { // $ ResourceMethod=text/xml
82+
}
83+
}
84+
85+
@Path("")
86+
public class JakartaRs3 implements JakartaRsInterface { // $ RootResourceClass
87+
public JakartaRs3() { // $ InjectableConstructor
88+
}
89+
90+
@Override
91+
public int Get() { // $ ResourceMethod ResourceMethodOnResourceClass
92+
return 1; // $ XssSink
93+
}
94+
95+
@Override
96+
public void Post() { // $ ResourceMethod ResourceMethodOnResourceClass
97+
}
98+
99+
@Produces("application/json") // $ ProducesAnnotation=application/json
100+
@Override
101+
public double Delete() { // not a resource method because it has a jax-rs annotation, so it doesn't inherit any jax-rs annotations
102+
return 1.0;
103+
}
104+
105+
@Produces(MediaType.TEXT_HTML) // $ ProducesAnnotation=text/html
106+
@Override
107+
public void Put() { // not a resource method because it has a jax-rs annotation, so it doesn't inherit any jax-rs annotations
108+
}
109+
110+
@Override
111+
public void Options() { // $ ResourceMethod ResourceMethodOnResourceClass
112+
}
113+
114+
@Override
115+
public void Head() { // $ ResourceMethod ResourceMethodOnResourceClass
116+
}
117+
118+
119+
@Path("")
120+
NonRootResourceClassJakarta subResourceLocator() { // $ SubResourceLocator
121+
return null;
122+
}
123+
124+
public class NonRootResourceClassJakarta { // $ NonRootResourceClass
125+
@GET
126+
int Get() { // $ ResourceMethod ResourceMethodOnResourceClass
127+
return 0; // $ XssSink
128+
}
129+
130+
@Produces("text/html") // $ ProducesAnnotation=text/html
131+
@POST
132+
boolean Post() { // $ ResourceMethod=text/html ResourceMethodOnResourceClass
133+
return false; // $ XssSink
134+
}
135+
136+
@Produces(MediaType.TEXT_PLAIN) // $ ProducesAnnotation=text/plain
137+
@DELETE
138+
double Delete() { // $ ResourceMethod=text/plain ResourceMethodOnResourceClass
139+
return 0.0;
140+
}
141+
142+
@Path("")
143+
AnotherNonRootResourceClassJakarta subResourceLocator1() { // $ SubResourceLocator
144+
return null;
145+
}
146+
147+
@GET
148+
@Path("")
149+
NotAResourceClass1Jakarta NotASubResourceLocator1() { // $ ResourceMethod ResourceMethodOnResourceClass
150+
return null; // $ XssSink
151+
}
152+
153+
@GET
154+
NotAResourceClass2Jakarta NotASubResourceLocator2() { // $ ResourceMethod ResourceMethodOnResourceClass
155+
return null; // $ XssSink
156+
}
157+
158+
NotAResourceClass2Jakarta NotASubResourceLocator3() {
159+
return null;
160+
}
161+
}
162+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import java.io.InputStream;
2+
import java.io.IOException;
3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.Type;
5+
import jakarta.ws.rs.GET;
6+
import jakarta.ws.rs.POST;
7+
import jakarta.ws.rs.DELETE;
8+
import jakarta.ws.rs.PUT;
9+
import jakarta.ws.rs.OPTIONS;
10+
import jakarta.ws.rs.HEAD;
11+
import jakarta.ws.rs.Path;
12+
import jakarta.ws.rs.BeanParam;
13+
import jakarta.ws.rs.CookieParam;
14+
import jakarta.ws.rs.FormParam;
15+
import jakarta.ws.rs.HeaderParam;
16+
import jakarta.ws.rs.MatrixParam;
17+
import jakarta.ws.rs.PathParam;
18+
import jakarta.ws.rs.Produces;
19+
import jakarta.ws.rs.QueryParam;
20+
import jakarta.ws.rs.client.Client;
21+
import jakarta.ws.rs.core.Context;
22+
import jakarta.ws.rs.core.MediaType;
23+
import jakarta.ws.rs.core.MultivaluedMap;
24+
import jakarta.ws.rs.core.Response;
25+
import jakarta.ws.rs.ext.MessageBodyReader;
26+
27+
// By the JAX-RS spec, this is not a resource class because it doesn't
28+
// have a @Path annotation. Inheritance of class or interface annotations
29+
// is not supported in JAX-RS. However, this is a resource class for some
30+
// implementations, like Apache CXF, that allow inheritance of JAX-RS
31+
// annotations on classes and interfaces.
32+
public class JakartaRs4 implements JakartaRsInterface { // $ RootResourceClass
33+
public JakartaRs4() { // $ InjectableConstructor
34+
}
35+
36+
@Override
37+
public int Get() { // $ ResourceMethod ResourceMethodOnResourceClass
38+
return 1; // $ XssSink
39+
}
40+
41+
@Override
42+
public void Post() { // $ ResourceMethod ResourceMethodOnResourceClass
43+
}
44+
45+
@Produces("application/json") // $ ProducesAnnotation=application/json
46+
@Override
47+
public double Delete() { // not a resource method because it has a jax-rs annotation, so it doesn't inherit any jax-rs annotations
48+
return 1.0;
49+
}
50+
51+
@Produces(MediaType.TEXT_HTML) // $ ProducesAnnotation=text/html
52+
@Override
53+
public void Put() { // not a resource method because it has a jax-rs annotation, so it doesn't inherit any jax-rs annotations
54+
}
55+
56+
@Override
57+
public void Options() { // $ ResourceMethod ResourceMethodOnResourceClass
58+
}
59+
60+
@Override
61+
public void Head() { // $ ResourceMethod ResourceMethod ResourceMethodOnResourceClass
62+
}
63+
64+
65+
@Path("")
66+
NonRootResourceClassJakarta subResourceLocator() {
67+
return null;
68+
}
69+
70+
public class NonRootResourceClassJakarta { // $ NonRootResourceClass
71+
@GET
72+
int Get() { // $ ResourceMethod ResourceMethodOnResourceClass
73+
return 0; // $ XssSink
74+
}
75+
76+
@Produces("text/html") // $ ProducesAnnotation=text/html
77+
@POST
78+
boolean Post() { // $ ResourceMethod=text/html ResourceMethodOnResourceClass
79+
return false; // $ XssSink
80+
}
81+
82+
@Produces(MediaType.TEXT_PLAIN) // $ ProducesAnnotation=text/plain
83+
@DELETE
84+
double Delete() { // $ ResourceMethod=text/plain ResourceMethodOnResourceClass
85+
return 0.0;
86+
}
87+
88+
@Path("")
89+
AnotherNonRootResourceClassJakarta subResourceLocator1() { // $ SubResourceLocator
90+
return null;
91+
}
92+
93+
@GET
94+
@Path("")
95+
NotAResourceClass1Jakarta NotASubResourceLocator1() { // $ ResourceMethod ResourceMethodOnResourceClass
96+
return null; // $ XssSink
97+
}
98+
99+
@GET
100+
NotAResourceClass2Jakarta NotASubResourceLocator2() { // $ ResourceMethod ResourceMethodOnResourceClass
101+
return null; // $ XssSink
102+
}
103+
104+
NotAResourceClass2Jakarta NotASubResourceLocator3() {
105+
return null;
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)