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.internal.ClassUtils.*; 016import static org.apache.juneau.httppart.bean.Utils.*; 017import static org.apache.juneau.httppart.HttpPartType.*; 018 019import java.lang.reflect.*; 020import java.util.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.http.annotation.*; 024import org.apache.juneau.httppart.*; 025import org.apache.juneau.internal.*; 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 m The method containing the parameter or parameter type annotated with {@link Request}. 036 * @param i The parameter index. 037 * @param ps 038 * Configuration information used to instantiate part serializers and part parsers. 039 * <br>Can be <jk>null</jk>. 040 * @return Metadata about the parameter, or <jk>null</jk> if parameter or parameter type not annotated with {@link Request}. 041 */ 042 public static RequestBeanMeta create(Method m, int i, PropertyStore ps) { 043 if (! hasAnnotation(Request.class, m, i)) 044 return null; 045 return new RequestBeanMeta.Builder(ps).apply(m, i).build(); 046 } 047 048 /** 049 * Create metadata from specified class. 050 * 051 * @param c The class annotated with {@link Request}. 052 * @param ps 053 * Configuration information used to instantiate part serializers and part parsers. 054 * <br>Can be <jk>null</jk>. 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, PropertyStore ps) { 058 if (! hasAnnotation(Request.class, c)) 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 = ClassUtils.newInstance(HttpPartSerializer.class, b.serializer, true, b.ps); 075 this.parser = ClassUtils.newInstance(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(Method m, int i) { 094 return apply(m.getParameterTypes()[i]).apply(getAnnotation(Request.class, m, i)); 095 } 096 097 Builder apply(Class<?> c) { 098 apply(getAnnotation(Request.class, c)); 099 this.cm = BeanContext.DEFAULT.getClassMeta(c); 100 for (Method m : ClassUtils.getAllMethods(c, false)) { 101 if (isPublic(m)) { 102 assertNoAnnotations(m, Request.class, ResponseHeader.class, ResponseBody.class, ResponseStatus.class); 103 String n = m.getName(); 104 if (hasAnnotation(Body.class, m)) { 105 assertNoArgs(m, Body.class); 106 assertReturnNotVoid(m, Body.class); 107 properties.put(n, RequestBeanPropertyMeta.create(BODY, Body.class, m)); 108 } else if (hasAnnotation(Header.class, m)) { 109 assertNoArgs(m, Header.class); 110 assertReturnNotVoid(m, Header.class); 111 properties.put(n, RequestBeanPropertyMeta.create(HEADER, Header.class, m)); 112 } else if (hasAnnotation(Query.class, m)) { 113 assertNoArgs(m, Query.class); 114 assertReturnNotVoid(m, Query.class); 115 properties.put(n, RequestBeanPropertyMeta.create(QUERY, Query.class, m)); 116 } else if (hasAnnotation(FormData.class, m)) { 117 assertNoArgs(m, FormData.class); 118 assertReturnNotVoid(m, FormData.class); 119 properties.put(n, RequestBeanPropertyMeta.create(FORMDATA, FormData.class, m)); 120 } else if (hasAnnotation(Path.class, m)) { 121 assertNoArgs(m, Path.class); 122 assertReturnNotVoid(m, Path.class); 123 properties.put(n, RequestBeanPropertyMeta.create(PATH, Path.class, m)); 124 } 125 } 126 } 127 return this; 128 } 129 130 Builder apply(Request a) { 131 if (a != null) { 132 if (a.partSerializer() != HttpPartSerializer.Null.class) 133 serializer = a.partSerializer(); 134 if (a.partParser() != HttpPartParser.Null.class) 135 parser = a.partParser(); 136 } 137 return this; 138 } 139 140 RequestBeanMeta build() { 141 return new RequestBeanMeta(this); 142 } 143 } 144 145 /** 146 * Returns metadata about the class. 147 * 148 * @return Metadata about the class. 149 */ 150 public ClassMeta<?> getClassMeta() { 151 return cm; 152 } 153 154 /** 155 * Returns metadata about the bean property with the specified property name. 156 * 157 * @param name The bean property name. 158 * @return Metadata about the bean property, or <jk>null</jk> if none found. 159 */ 160 public RequestBeanPropertyMeta getProperty(String name) { 161 return properties.get(name); 162 } 163 164 /** 165 * Returns all the annotated methods on this bean. 166 * 167 * @return All the annotated methods on this bean. 168 */ 169 public Collection<RequestBeanPropertyMeta> getProperties() { 170 return properties.values(); 171 } 172}