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