001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.httppart.bean; 014 015import static org.apache.juneau.httppart.bean.Utils.*; 016import static org.apache.juneau.internal.ClassUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018import static org.apache.juneau.httppart.HttpPartType.*; 019 020import java.util.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.cp.*; 024import org.apache.juneau.http.annotation.*; 025import org.apache.juneau.httppart.*; 026import org.apache.juneau.reflect.*; 027 028/** 029 * Represents the metadata gathered from a parameter or class annotated with {@link Request}. 030 * 031 * <h5 class='section'>See Also:</h5><ul> 032 * <li class='link'><a class="doclink" href="../../../../../index.html#jm.HttpPartSerializersParsers">HTTP Part Serializers and Parsers</a> 033 * </ul> 034 */ 035public class RequestBeanMeta { 036 037 /** 038 * Create metadata from specified parameter. 039 * 040 * @param mpi The method parameter. 041 * @param annotations The annotations to apply to any new part serializers or parsers. 042 * @return Metadata about the parameter, or <jk>null</jk> if parameter or parameter type not annotated with {@link Request}. 043 */ 044 public static RequestBeanMeta create(ParamInfo mpi, AnnotationWorkList annotations) { 045 if (mpi.hasNoAnnotation(Request.class)) 046 return null; 047 return new RequestBeanMeta.Builder(annotations).apply(mpi).build(); 048 } 049 050 /** 051 * Create metadata from specified class. 052 * 053 * @param c The class annotated with {@link Request}. 054 * @param annotations The annotations to apply to any new part serializers or parsers. 055 * @return Metadata about the class, or <jk>null</jk> if class not annotated with {@link Request}. 056 */ 057 public static RequestBeanMeta create(Class<?> c, AnnotationWorkList annotations) { 058 ClassInfo ci = ClassInfo.of(c); 059 if (ci.hasNoAnnotation(Request.class)) 060 return null; 061 return new RequestBeanMeta.Builder(annotations).apply(c).build(); 062 } 063 064 //----------------------------------------------------------------------------------------------------------------- 065 // Instance 066 //----------------------------------------------------------------------------------------------------------------- 067 068 private final ClassMeta<?> cm; 069 private final Map<String,RequestBeanPropertyMeta> properties; 070 private final HttpPartSerializer serializer; 071 private final HttpPartParser parser; 072 073 RequestBeanMeta(Builder b) { 074 this.cm = b.cm; 075 this.serializer = b.serializer.orElse(null); 076 this.parser = b.parser.orElse(null); 077 Map<String,RequestBeanPropertyMeta> properties = map(); 078 b.properties.forEach((k,v) -> properties.put(k, v.build(serializer, parser))); 079 this.properties = unmodifiable(properties); 080 } 081 082 static class Builder { 083 ClassMeta<?> cm; 084 AnnotationWorkList annotations; 085 BeanCreator<HttpPartSerializer> serializer = BeanCreator.of(HttpPartSerializer.class); 086 BeanCreator<HttpPartParser> parser = BeanCreator.of(HttpPartParser.class); 087 Map<String,RequestBeanPropertyMeta.Builder> properties = map(); 088 089 Builder(AnnotationWorkList annotations) { 090 this.annotations = annotations; 091 } 092 093 Builder apply(ParamInfo mpi) { 094 return apply(mpi.getParameterType().inner()).apply(mpi.getAnnotation(Request.class)); 095 } 096 097 Builder apply(Class<?> c) { 098 this.cm = BeanContext.DEFAULT.getClassMeta(c); 099 apply(cm.getLastAnnotation(Request.class)); 100 cm.getInfo().forEachPublicMethod(x -> true, x -> { 101 String n = x.getSimpleName(); 102 if (x.hasAnnotation(Header.class)) { 103 assertNoArgs(x, Header.class); 104 assertReturnNotVoid(x, Header.class); 105 properties.put(n, RequestBeanPropertyMeta.create(HEADER, Header.class, x)); 106 } else if (x.hasAnnotation(Query.class)) { 107 assertNoArgs(x, Query.class); 108 assertReturnNotVoid(x, Query.class); 109 properties.put(n, RequestBeanPropertyMeta.create(QUERY, Query.class, x)); 110 } else if (x.hasAnnotation(FormData.class)) { 111 assertNoArgs(x, FormData.class); 112 assertReturnNotVoid(x, FormData.class); 113 properties.put(n, RequestBeanPropertyMeta.create(FORMDATA, FormData.class, x)); 114 } else if (x.hasAnnotation(Path.class)) { 115 assertNoArgs(x, Path.class); 116 assertReturnNotVoid(x, Path.class); 117 properties.put(n, RequestBeanPropertyMeta.create(PATH, Path.class, x)); 118 } else if (x.hasAnnotation(Content.class)) { 119 assertNoArgs(x, Content.class); 120 assertReturnNotVoid(x, Content.class); 121 properties.put(n, RequestBeanPropertyMeta.create(BODY, Content.class, x)); 122 } 123 }); 124 return this; 125 } 126 127 Builder apply(Request a) { 128 if (a != null) { 129 if (isNotVoid(a.serializer())) 130 serializer.type(a.serializer()); 131 if (isNotVoid(a.parser())) 132 parser.type(a.parser()); 133 } 134 return this; 135 } 136 137 RequestBeanMeta build() { 138 return new RequestBeanMeta(this); 139 } 140 } 141 142 /** 143 * Returns metadata about the class. 144 * 145 * @return Metadata about the class. 146 */ 147 public ClassMeta<?> getClassMeta() { 148 return cm; 149 } 150 151 /** 152 * Returns metadata about the bean property with the specified property name. 153 * 154 * @param name The bean property name. 155 * @return Metadata about the bean property, or <jk>null</jk> if none found. 156 */ 157 public RequestBeanPropertyMeta getProperty(String name) { 158 return properties.get(name); 159 } 160 161 /** 162 * Returns all the annotated methods on this bean. 163 * 164 * @return All the annotated methods on this bean. 165 */ 166 public Collection<RequestBeanPropertyMeta> getProperties() { 167 return properties.values(); 168 } 169}