001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.arg; 018 019import static org.apache.juneau.commons.utils.Utils.*; 020import static org.apache.juneau.http.annotation.PathRemainderAnnotation.*; 021 022import java.lang.reflect.*; 023 024import org.apache.juneau.*; 025import org.apache.juneau.commons.reflect.*; 026import org.apache.juneau.http.annotation.*; 027import org.apache.juneau.httppart.*; 028import org.apache.juneau.rest.*; 029import org.apache.juneau.rest.annotation.*; 030import org.apache.juneau.rest.httppart.*; 031import org.apache.juneau.rest.util.*; 032 033/** 034 * Resolves method parameters annotated with {@link PathRemainder} on {@link RestOp}-annotated Java methods. 035 * 036 * <p> 037 * This is a specialized version of {@link PathArg} for the path remainder (the part matched by {@code /*}). 038 * It's functionally equivalent to using {@code @Path("/*")}, but provides a more intuitive annotation name. 039 * 040 * <p> 041 * The parameter value is resolved using: 042 * <p class='bjava'> 043 * <jv>opSession</jv> 044 * .{@link RestOpSession#getRequest() getRequest}() 045 * .{@link RestRequest#getPathParams() getPathParams}() 046 * .{@link RequestPathParams#get(String) get}(<js>"/*"</js>) 047 * .{@link RequestPathParam#as(Class) as}(<jv>type</jv>); 048 * </p> 049 * 050 * <p> 051 * {@link HttpPartSchema schema} is derived from the {@link PathRemainder} annotation. 052 * 053 * <h5 class='section'>See Also:</h5><ul> 054 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JavaMethodParameters">Java Method Parameters</a> 055 * <li class='ja'>{@link PathRemainder} 056 * <li class='jc'>{@link PathArg} 057 * </ul> 058 * 059 * @since 9.2.0 060 */ 061public class PathRemainderArg implements RestOpArg { 062 063 private static final AnnotationProvider AP = AnnotationProvider.INSTANCE; 064 065 /** 066 * Static creator. 067 * 068 * @param paramInfo The Java method parameter being resolved. 069 * @param annotations The annotations to apply to any new part parsers. 070 * @param pathMatcher Path matcher for the specified method (not used, but included for BeanStore compatibility). 071 * @return A new {@link PathRemainderArg}, or <jk>null</jk> if the parameter is not annotated with {@link PathRemainder}. 072 */ 073 public static PathRemainderArg create(ParameterInfo paramInfo, AnnotationWorkList annotations, UrlPathMatcher pathMatcher) { 074 if (AP.has(PathRemainder.class, paramInfo)) 075 return new PathRemainderArg(paramInfo, annotations); 076 return null; 077 } 078 079 private final HttpPartParser partParser; 080 private final HttpPartSchema schema; 081 private final String def; 082 083 private final Type type; 084 085 /** 086 * Constructor. 087 * 088 * @param paramInfo The Java method parameter being resolved. 089 * @param annotations The annotations to apply to any new part parsers. 090 */ 091 protected PathRemainderArg(ParameterInfo paramInfo, AnnotationWorkList annotations) { 092 this.def = findDef(paramInfo).orElse(null); 093 this.type = paramInfo.getParameterType().innerType(); 094 this.schema = HttpPartSchema.create(PathRemainder.class, paramInfo); 095 var pp = schema.getParser(); 096 this.partParser = nn(pp) ? HttpPartParser.creator().type(pp).apply(annotations).create() : null; 097 } 098 099 @Override /* Overridden from RestOpArg */ 100 public Object resolve(RestOpSession opSession) throws Exception { 101 var req = opSession.getRequest(); 102 var ps = partParser == null ? req.getPartParserSession() : partParser.getPartSession(); 103 // The path remainder is stored under the name "/*" 104 return req.getPathParams().get("/*").parser(ps).schema(schema).def(def).as(type).orElse(null); 105 } 106}