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.httppart.bean; 018 019import static org.apache.juneau.commons.reflect.ReflectionUtils.*; 020import static org.apache.juneau.commons.utils.ClassUtils.*; 021import static org.apache.juneau.commons.utils.CollectionUtils.*; 022import static org.apache.juneau.commons.utils.Utils.*; 023import static org.apache.juneau.httppart.HttpPartType.*; 024import static org.apache.juneau.httppart.bean.MethodInfoUtils.*; 025 026import java.util.*; 027 028import org.apache.juneau.*; 029import org.apache.juneau.commons.reflect.*; 030import org.apache.juneau.cp.*; 031import org.apache.juneau.http.annotation.*; 032import org.apache.juneau.httppart.*; 033 034/** 035 * Represents the metadata gathered from a parameter or class annotated with {@link Request}. 036 * 037 * <h5 class='section'>See Also:</h5><ul> 038 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HttpPartSerializersParsers">HTTP Part Serializers and Parsers</a> 039 * </ul> 040 */ 041public class RequestBeanMeta { 042 043 private static final AnnotationProvider AP = AnnotationProvider.INSTANCE; 044 045 static class Builder { 046 ClassMeta<?> cm; 047 AnnotationWorkList annotations; 048 BeanCreator<HttpPartSerializer> serializer = BeanCreator.of(HttpPartSerializer.class); 049 BeanCreator<HttpPartParser> parser = BeanCreator.of(HttpPartParser.class); 050 Map<String,RequestBeanPropertyMeta.Builder> properties = map(); 051 052 Builder(AnnotationWorkList annotations) { 053 this.annotations = annotations; 054 } 055 056 Builder apply(Class<?> c) { 057 this.cm = BeanContext.DEFAULT.getClassMeta(c); 058 var ap = cm.getBeanContext().getAnnotationProvider(); 059 apply(ap.find(Request.class, cm).stream().findFirst().map(x -> x.inner()).orElse(null)); 060 cm.getPublicMethods().stream().forEach(x -> { 061 var n = x.getSimpleName(); 062 if (x.hasAnnotation(Header.class)) { 063 assertNoArgs(x, Header.class); 064 assertReturnNotVoid(x, Header.class); 065 properties.put(n, RequestBeanPropertyMeta.create(HEADER, Header.class, x)); 066 } else if (x.hasAnnotation(Query.class)) { 067 assertNoArgs(x, Query.class); 068 assertReturnNotVoid(x, Query.class); 069 properties.put(n, RequestBeanPropertyMeta.create(QUERY, Query.class, x)); 070 } else if (x.hasAnnotation(FormData.class)) { 071 assertNoArgs(x, FormData.class); 072 assertReturnNotVoid(x, FormData.class); 073 properties.put(n, RequestBeanPropertyMeta.create(FORMDATA, FormData.class, x)); 074 } else if (x.hasAnnotation(Path.class)) { 075 assertNoArgs(x, Path.class); 076 assertReturnNotVoid(x, Path.class); 077 properties.put(n, RequestBeanPropertyMeta.create(PATH, Path.class, x)); 078 } else if (x.hasAnnotation(Content.class)) { 079 assertNoArgs(x, Content.class); 080 assertReturnNotVoid(x, Content.class); 081 properties.put(n, RequestBeanPropertyMeta.create(BODY, Content.class, x)); 082 } 083 }); 084 return this; 085 } 086 087 Builder apply(ParameterInfo mpi) { 088 return apply(mpi.getParameterType().inner()).apply(AP.find(Request.class, mpi).stream().findFirst().map(AnnotationInfo::inner).orElse(null)); 089 } 090 091 Builder apply(Request a) { 092 if (nn(a)) { 093 if (isNotVoid(a.serializer())) 094 serializer.type(a.serializer()); 095 if (isNotVoid(a.parser())) 096 parser.type(a.parser()); 097 } 098 return this; 099 } 100 101 RequestBeanMeta build() { 102 return new RequestBeanMeta(this); 103 } 104 } 105 106 /** 107 * Create metadata from specified class. 108 * 109 * @param c The class annotated with {@link Request}. 110 * @param annotations The annotations to apply to any new part serializers or parsers. 111 * @return Metadata about the class, or <jk>null</jk> if class not annotated with {@link Request}. 112 */ 113 public static RequestBeanMeta create(Class<?> c, AnnotationWorkList annotations) { 114 var ci = info(c); 115 if (! ci.hasAnnotation(Request.class)) 116 return null; 117 return new RequestBeanMeta.Builder(annotations).apply(c).build(); 118 } 119 120 /** 121 * Create metadata from specified parameter. 122 * 123 * @param mpi The method parameter. 124 * @param annotations The annotations to apply to any new part serializers or parsers. 125 * @return Metadata about the parameter, or <jk>null</jk> if parameter or parameter type not annotated with {@link Request}. 126 */ 127 public static RequestBeanMeta create(ParameterInfo mpi, AnnotationWorkList annotations) { 128 if (! AP.has(Request.class, mpi)) 129 return null; 130 return new RequestBeanMeta.Builder(annotations).apply(mpi).build(); 131 } 132 133 private final ClassMeta<?> cm; 134 private final Map<String,RequestBeanPropertyMeta> properties; 135 private final HttpPartSerializer serializer; 136 137 private final HttpPartParser parser; 138 139 RequestBeanMeta(Builder b) { 140 cm = b.cm; 141 serializer = b.serializer.orElse(null); 142 parser = b.parser.orElse(null); 143 Map<String,RequestBeanPropertyMeta> pm = map(); 144 b.properties.forEach((k, v) -> pm.put(k, v.build(serializer, parser))); 145 properties = u(pm); 146 } 147 148 /** 149 * Returns metadata about the class. 150 * 151 * @return Metadata about the class. 152 */ 153 public ClassMeta<?> getClassMeta() { return cm; } 154 155 /** 156 * Returns all the annotated methods on this bean. 157 * 158 * @return All the annotated methods on this bean. 159 */ 160 public Collection<RequestBeanPropertyMeta> getProperties() { return properties.values(); } 161 162 /** 163 * Returns metadata about the bean property with the specified property name. 164 * 165 * @param name The bean property name. 166 * @return Metadata about the bean property, or <jk>null</jk> if none found. 167 */ 168 public RequestBeanPropertyMeta getProperty(String name) { 169 return properties.get(name); 170 } 171}