Skip to content

Commit 6ac445e

Browse files
committed
ACC-2100 refactor PropertyNotFoundException, IllegalMediaTypeException and UnsupportedMediaTypeException
Let them extend ResponseStatusException and UnsupportedMediaTypeStatusException from spring web mvc. So that they will automatically be converted to problem details
1 parent 3d65cd4 commit 6ac445e

File tree

8 files changed

+86
-73
lines changed

8 files changed

+86
-73
lines changed

contentgrid-appserver-rest/src/main/java/com/contentgrid/appserver/rest/converter/AbstractHttpServletRequestConverter.java

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,52 @@
11
package com.contentgrid.appserver.rest.converter;
22

33
import jakarta.servlet.http.HttpServletRequest;
4+
import java.io.IOException;
5+
import java.util.List;
46
import java.util.Optional;
7+
import lombok.Getter;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.http.MediaType;
510

6-
public interface HttpServletRequestConverter<T> {
11+
@Getter
12+
@RequiredArgsConstructor
13+
public abstract class HttpServletRequestConverter<T> {
14+
15+
private final List<MediaType> supportedMediaTypes;
16+
17+
HttpServletRequestConverter(MediaType... supportedMediaTypes) {
18+
this(List.of(supportedMediaTypes));
19+
}
720

821
/**
9-
* Returns whether this converter is able to convert the given request.
10-
* Note: the body InputStream can not yet be consumed.
22+
* Returns whether this converter is able to convert the given media type of the request.
1123
*
12-
* @param request the request to check
13-
* @return whether this converter is able to convert the given request
24+
* @param mediaType the media type of the request to check
25+
* @return whether this converter is able to convert the given media type of the request
1426
*/
15-
boolean canRead(HttpServletRequest request);
27+
public boolean canRead(MediaType mediaType) {
28+
return supportedMediaTypes.stream().anyMatch(supportedMediaType -> supportedMediaType.includes(mediaType));
29+
}
1630

1731
/**
1832
* Converts a {@link HttpServletRequest} and returns an {@link Optional} containing the converted request.
1933
*
2034
* @param request the request to be converted
2135
* @return an {@link Optional} containing the converted request, empty if it could not be converted
2236
*/
23-
Optional<T> convert(HttpServletRequest request);
37+
public Optional<T> convert(HttpServletRequest request) {
38+
try {
39+
return Optional.ofNullable(read(request));
40+
} catch (IOException e) {
41+
return Optional.empty();
42+
}
43+
}
44+
45+
/**
46+
* Converts a {@link HttpServletRequest}.
47+
*
48+
* @param request the request to be converted
49+
* @return the converted request
50+
*/
51+
protected abstract T read(HttpServletRequest request) throws IOException;
2452
}

contentgrid-appserver-rest/src/main/java/com/contentgrid/appserver/rest/converter/UriListHttpServletRequestConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import org.springframework.stereotype.Component;
1212

1313
@Component
14-
public class UriListHttpServletRequestConverter extends AbstractHttpServletRequestConverter<List<URI>> {
14+
public class UriListHttpServletRequestConverter extends HttpServletRequestConverter<List<URI>> {
1515

1616
public UriListHttpServletRequestConverter() {
1717
super(MediaType.parseMediaType("text/uri-list"));
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.contentgrid.appserver.rest.exception;
2+
3+
import java.util.List;
4+
import org.springframework.http.MediaType;
5+
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
6+
7+
public class IllegalMediaTypeException extends UnsupportedMediaTypeStatusException {
8+
9+
public IllegalMediaTypeException(String mediaType, List<MediaType> supportedMediaTypes) {
10+
super("Media type %s could not be parsed".formatted(mediaType), supportedMediaTypes);
11+
}
12+
13+
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.contentgrid.appserver.rest.exception;
22

33
import com.contentgrid.appserver.application.model.values.PathSegmentName;
4+
import org.springframework.http.HttpStatus;
5+
import org.springframework.web.server.ResponseStatusException;
46

5-
public class PropertyNotFoundException extends RuntimeException {
7+
public class PropertyNotFoundException extends ResponseStatusException {
68

79
public PropertyNotFoundException(PathSegmentName name) {
8-
super("Property path with name '%s' not found".formatted(name));
10+
super(HttpStatus.NOT_FOUND, "Property path with name '%s' not found".formatted(name));
11+
getBody().setProperty("property", name.getValue());
912
}
1013

1114
}
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.contentgrid.appserver.rest.exception;
22

3-
public class UnsupportedMediaTypeException extends RuntimeException {
3+
import java.util.List;
4+
import org.springframework.http.MediaType;
5+
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
46

5-
public UnsupportedMediaTypeException(String mediaType) {
6-
super("Media type %s not supported".formatted(mediaType));
7+
public class UnsupportedMediaTypeException extends UnsupportedMediaTypeStatusException {
8+
9+
public UnsupportedMediaTypeException(MediaType mediaType, List<MediaType> supportedMediaTypes) {
10+
super(mediaType, supportedMediaTypes);
711
}
812

913
}

contentgrid-appserver-rest/src/main/java/com/contentgrid/appserver/rest/property/PropertyUtils.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,22 @@ public static <T extends PropertyRequestHandler> ResponseEntity<Object> handlePr
2626
var entity = application.getEntityByPathSegment(entityName)
2727
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Entity %s does not exist".formatted(entityName)));
2828

29-
var propertyExists = false;
30-
Throwable cause = null;
29+
UnsupportedMediaTypeException unsupportedMediaTypeException = null;
3130

3231
for (var requestHandler : requestHandlers) {
3332
try {
3433
return function.apply(requestHandler, entity);
3534
} catch (PropertyNotFoundException e) {
36-
if (cause == null) {
37-
cause = e;
38-
}
35+
// skip
3936
} catch (UnsupportedMediaTypeException e) {
40-
propertyExists = true;
41-
cause = e;
37+
unsupportedMediaTypeException = e;
4238
}
4339
}
4440

45-
if (propertyExists) {
46-
throw new ResponseStatusException(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "Unsupported media type", cause);
41+
if (unsupportedMediaTypeException != null) {
42+
throw unsupportedMediaTypeException;
4743
} else {
48-
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
49-
"Property %s does not exist on entity %s".formatted(propertyName, entityName), cause);
44+
throw new PropertyNotFoundException(propertyName);
5045
}
5146
}
5247
}

contentgrid-appserver-rest/src/main/java/com/contentgrid/appserver/rest/property/handler/AbstractPropertyRequestHandler.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.contentgrid.appserver.application.model.values.PathSegmentName;
66
import com.contentgrid.appserver.query.engine.api.data.EntityId;
77
import com.contentgrid.appserver.rest.converter.HttpServletRequestConverter;
8+
import com.contentgrid.appserver.rest.exception.IllegalMediaTypeException;
89
import com.contentgrid.appserver.rest.exception.UnsupportedMediaTypeException;
910
import com.contentgrid.appserver.rest.exception.PropertyNotFoundException;
1011
import jakarta.servlet.http.HttpServletRequest;
@@ -14,7 +15,10 @@
1415
import lombok.Getter;
1516
import lombok.RequiredArgsConstructor;
1617
import org.springframework.http.HttpStatus;
18+
import org.springframework.http.InvalidMediaTypeException;
19+
import org.springframework.http.MediaType;
1720
import org.springframework.http.ResponseEntity;
21+
import org.springframework.util.InvalidMimeTypeException;
1822
import org.springframework.web.server.ResponseStatusException;
1923

2024
@RequiredArgsConstructor
@@ -68,14 +72,25 @@ public final ResponseEntity<Object> deleteProperty(Application application, Enti
6872
.orElseThrow(() -> new PropertyNotFoundException(propertyName));
6973
}
7074

71-
protected final ResponseEntity<Object> handleProperty(HttpServletRequest request, Function<T, ResponseEntity<Object>> function) throws UnsupportedMediaTypeException {
72-
if (!requestConverter.canRead(request)) {
73-
throw new UnsupportedMediaTypeException(request.getContentType());
74-
}
75+
protected final ResponseEntity<Object> handleProperty(HttpServletRequest request, Function<T, ResponseEntity<Object>> function)
76+
throws IllegalMediaTypeException, UnsupportedMediaTypeException {
77+
assertMediaTypeSupported(request);
7578
return requestConverter.convert(request).map(function)
7679
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid body"));
7780
}
7881

82+
private void assertMediaTypeSupported(HttpServletRequest request)
83+
throws IllegalMediaTypeException, UnsupportedMediaTypeException {
84+
try {
85+
var mediaType = MediaType.parseMediaType(request.getContentType());
86+
if (!requestConverter.canRead(mediaType)) {
87+
throw new UnsupportedMediaTypeException(mediaType, requestConverter.getSupportedMediaTypes());
88+
}
89+
} catch (InvalidMediaTypeException | InvalidMimeTypeException e) {
90+
throw new IllegalMediaTypeException(request.getContentType(), requestConverter.getSupportedMediaTypes());
91+
}
92+
}
93+
7994
protected abstract ResponseEntity<Object> getProperty(Application application, Entity entity, EntityId instanceId, P property);
8095

8196
protected abstract ResponseEntity<Object> postProperty(Application application, Entity entity, EntityId instanceId, P property, T body);

0 commit comments

Comments
 (0)