Skip to content

Commit

Permalink
feat: allow model resolvers to resolve both path variables and reques…
Browse files Browse the repository at this point in the history
…t params
  • Loading branch information
MiniDigger committed Jan 10, 2025
1 parent f6d7795 commit 1d8457a
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 57 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.papermc.hangar.controller.extras.resolvers.path.model;

import io.papermc.hangar.exceptions.HangarApiException;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ValueConstants;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver;
import org.springframework.web.servlet.HandlerMapping;

/**
* Model resolver that is able to resolve both path variables and request params
*
* @param <M> the model type
*/
public abstract class HangarModelResolver<M> extends AbstractNamedValueMethodArgumentResolver {

protected abstract Class<M> modelType();

@Override
public boolean supportsParameter(final @NotNull MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(PathVariable.class) && !parameter.hasParameterAnnotation(RequestParam.class)) {
return false;
}
return parameter.getParameterType().equals(this.modelType());
}

@Override
protected @NotNull NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
final PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
if (pathVariable != null) {
return new NamedValueInfo(pathVariable.name(), pathVariable.required(), ValueConstants.DEFAULT_NONE);
}
final RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
if (requestParam != null) {
return new NamedValueInfo(requestParam.name(), requestParam.required(), ValueConstants.DEFAULT_NONE);
}
throw new IllegalStateException("No PathVariable or RequestParam annotation found on parameter " + parameter.getParameterName() + " of method " + parameter.getMethod());
}

@Override
protected final @Nullable M resolveName(final @NotNull String name, final @NotNull MethodParameter parameter, final @NotNull NativeWebRequest request) throws Exception {
final PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
if (pathVariable != null) {
@SuppressWarnings("unchecked") final Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
final String param = uriTemplateVars != null ? uriTemplateVars.get(name) : null;
if (param == null) {
if (pathVariable.required()) {
throw new HangarApiException(HttpStatus.BAD_REQUEST, "Missing required path variable '" + name + "'");
}
return null;
}
return this.handleValue(this.resolveParameter(param, request), param, name, "path variable");
}
final RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
if (requestParam != null) {
final String[] paramArray = request.getParameterValues(name);
if (paramArray == null) {
if (requestParam.required()) {
throw new HangarApiException(HttpStatus.BAD_REQUEST, "Missing required request param '" + name + "'");
}
return null;
}
Assert.state(paramArray.length == 1, "Expected single value for parameter '" + name + "' but got " + paramArray.length);
return this.handleValue(this.resolveParameter(paramArray[0], request), paramArray[0], name, "request param");
}
return null;
}

private M handleValue(final M resolvedValue, final String value, final String name, final String type) {
if (resolvedValue == null) {
throw new HangarApiException(HttpStatus.NOT_FOUND, "Unknown value '" + value + "' for " + type + " '" + name + "'");
}
return resolvedValue;
}

protected abstract M resolveParameter(@NotNull String param, NativeWebRequest request);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package io.papermc.hangar.controller.extras.resolvers.path.model;

import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.db.projects.ProjectChannelTable;
import io.papermc.hangar.service.internal.projects.ChannelService;
import io.papermc.hangar.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.NativeWebRequest;

@Component
public class ProjectChannelResolver extends HangarModelPathVarResolver<ProjectChannelTable> {
public class ProjectChannelResolver extends HangarModelResolver<ProjectChannelTable> {

private final ChannelService channelService;

Expand All @@ -30,13 +28,9 @@ protected ProjectChannelTable resolveParameter(final @NotNull String param, fina
if (!StringUtils.isLong(param)) {
final Object projectId = request.getAttribute("projectId", NativeWebRequest.SCOPE_REQUEST);
if (!(projectId instanceof final Long projectIdLong)) {
throw new HangarApiException(HttpStatus.NOT_FOUND);
return null;
}
final ProjectChannelTable projectTable = this.channelService.getProjectChannel(projectIdLong, param);
if (projectTable != null) {
return projectTable;
}
throw new HangarApiException(HttpStatus.NOT_FOUND);
return this.channelService.getProjectChannel(projectIdLong, param);
}

return this.channelService.getProjectChannel(Long.parseLong(param));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package io.papermc.hangar.controller.extras.resolvers.path.model;

import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.db.projects.ProjectTable;
import io.papermc.hangar.service.internal.projects.ProjectService;
import io.papermc.hangar.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.NativeWebRequest;

@Component
public class ProjectTableResolver extends HangarModelPathVarResolver<ProjectTable> {
public class ProjectTableResolver extends HangarModelResolver<ProjectTable> {

private final ProjectService projectService;

Expand Down Expand Up @@ -41,6 +39,6 @@ protected ProjectTable resolveParameter(final @NotNull String param, final Nativ
return projectTable;
}

throw new HangarApiException(HttpStatus.NOT_FOUND);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package io.papermc.hangar.controller.extras.resolvers.path.model;

import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.db.versions.ProjectVersionTable;
import io.papermc.hangar.service.internal.versions.VersionService;
import io.papermc.hangar.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.NativeWebRequest;

@Component
public class ProjectVersionTableResolver extends HangarModelPathVarResolver<ProjectVersionTable> {
public class ProjectVersionTableResolver extends HangarModelResolver<ProjectVersionTable> {

private final VersionService versionService;

Expand All @@ -35,7 +33,7 @@ protected ProjectVersionTable resolveParameter(final @NotNull String param, fina
if (projectVersionTable == null) {
final Object projectId = request.getAttribute("projectId", NativeWebRequest.SCOPE_REQUEST);
if (!(projectId instanceof final Long projectIdLong)) {
throw new HangarApiException(HttpStatus.NOT_FOUND);
return null;
}
projectVersionTable = this.versionService.getProjectVersionTable(projectIdLong, param);
}
Expand All @@ -45,6 +43,6 @@ protected ProjectVersionTable resolveParameter(final @NotNull String param, fina
return projectVersionTable;
}

throw new HangarApiException(HttpStatus.NOT_FOUND);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package io.papermc.hangar.controller.extras.resolvers.path.model;

import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.model.db.UserTable;
import io.papermc.hangar.service.internal.users.UserService;
import io.papermc.hangar.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.NativeWebRequest;

@Component
public class UserTableResolver extends HangarModelPathVarResolver<UserTable> {
public class UserTableResolver extends HangarModelResolver<UserTable> {

private final UserService userService;

Expand Down Expand Up @@ -41,6 +39,6 @@ protected UserTable resolveParameter(final @NotNull String param, final NativeWe
return userTable;
}

throw new HangarApiException(HttpStatus.NOT_FOUND);
return null;
}
}

0 comments on commit 1d8457a

Please sign in to comment.