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.httppart.HttpPartType.*; 018import static org.apache.juneau.annotation.InvalidAnnotationException.*; 019 020import java.util.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.http.annotation.*; 024import org.apache.juneau.httppart.*; 025import org.apache.juneau.reflect.*; 026 027/** 028 * Represents the metadata gathered from a parameter or class annotated with {@link Request}. 029 */ 030public class RequestBeanMeta { 031 032 /** 033 * Create metadata from specified parameter. 034 * 035 * @param mpi The method parameter. 036 * @param ps 037 * Configuration information used to instantiate part serializers and part parsers. 038 * <br>Can be <jk>null</jk>. 039 * @return Metadata about the parameter, or <jk>null</jk> if parameter or parameter type not annotated with {@link Request}. 040 */ 041 public static RequestBeanMeta create(ParamInfo mpi, PropertyStore ps) { 042 if (! mpi.hasAnnotation(Request.class)) 043 return null; 044 return new RequestBeanMeta.Builder(ps).apply(mpi).build(); 045 } 046 047 /** 048 * Create metadata from specified class. 049 * 050 * @param c The class annotated with {@link Request}. 051 * @param ps 052 * Configuration information used to instantiate part serializers and part parsers. 053 * <br>Can be <jk>null</jk>. 054 * @return Metadata about the class, or <jk>null</jk> if class not annotated with {@link Request}. 055 */ 056 public static RequestBeanMeta create(Class<?> c, PropertyStore ps) { 057 ClassInfo ci = getClassInfo(c); 058 if (! ci.hasAnnotation(Request.class)) 059 return null; 060 return new RequestBeanMeta.Builder(ps).apply(c).build(); 061 } 062 063 //----------------------------------------------------------------------------------------------------------------- 064 // Instance 065 //----------------------------------------------------------------------------------------------------------------- 066 067 private final ClassMeta<?> cm; 068 private final Map<String,RequestBeanPropertyMeta> properties; 069 private final HttpPartSerializer serializer; 070 private final HttpPartParser parser; 071 072 RequestBeanMeta(Builder b) { 073 this.cm = b.cm; 074 this.serializer = castOrCreate(HttpPartSerializer.class, b.serializer, true, b.ps); 075 this.parser = castOrCreate(HttpPartParser.class, b.parser, true, b.ps); 076 Map<String,RequestBeanPropertyMeta> properties = new LinkedHashMap<>(); 077 for (Map.Entry<String,RequestBeanPropertyMeta.Builder> e : b.properties.entrySet()) 078 properties.put(e.getKey(), e.getValue().build(serializer, parser)); 079 this.properties = Collections.unmodifiableMap(properties); 080 } 081 082 static class Builder { 083 ClassMeta<?> cm; 084 PropertyStore ps; 085 Class<? extends HttpPartSerializer> serializer; 086 Class<? extends HttpPartParser> parser; 087 Map<String,RequestBeanPropertyMeta.Builder> properties = new LinkedHashMap<>(); 088 089 Builder(PropertyStore ps) { 090 this.ps = ps; 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 ClassInfo ci = getClassInfo(c); 099 apply(ci.getAnnotation(Request.class)); 100 this.cm = BeanContext.DEFAULT.getClassMeta(c); 101 for (MethodInfo m : cm.getInfo().getAllMethods()) { 102 103 if (m.isPublic()) { 104 assertNoInvalidAnnotations(m, ResponseHeader.class, ResponseBody.class, ResponseStatus.class); 105 String n = m.getSimpleName(); 106 if (m.hasAnnotation(Body.class)) { 107 assertNoArgs(m, Body.class); 108 assertReturnNotVoid(m, Body.class); 109 properties.put(n, RequestBeanPropertyMeta.create(BODY, Body.class, m)); 110 } else if (m.hasAnnotation(Header.class)) { 111 assertNoArgs(m, Header.class); 112 assertReturnNotVoid(m, Header.class); 113 properties.put(n, RequestBeanPropertyMeta.create(HEADER, Header.class, m)); 114 } else if (m.hasAnnotation(Query.class)) { 115 assertNoArgs(m, Query.class); 116 assertReturnNotVoid(m, Query.class); 117 properties.put(n, RequestBeanPropertyMeta.create(QUERY, Query.class, m)); 118 } else if (m.hasAnnotation(FormData.class)) { 119 assertNoArgs(m, FormData.class); 120 assertReturnNotVoid(m, FormData.class); 121 properties.put(n, RequestBeanPropertyMeta.create(FORMDATA, FormData.class, m)); 122 } else if (m.hasAnnotation(Path.class)) { 123 assertNoArgs(m, Path.class); 124 assertReturnNotVoid(m, Path.class); 125 properties.put(n, RequestBeanPropertyMeta.create(PATH, Path.class, m)); 126 } 127 } 128 } 129 return this; 130 } 131 132 Builder apply(Request a) { 133 if (a != null) { 134 if (a.partSerializer() != HttpPartSerializer.Null.class) 135 serializer = a.partSerializer(); 136 if (a.partParser() != HttpPartParser.Null.class) 137 parser = a.partParser(); 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}