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 = ClassInfo.of(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.getLastAnnotation(Request.class)); 095 } 096 097 Builder apply(Class<?> c) { 098 this.cm = BeanContext.DEFAULT.getClassMeta(c); 099 apply(cm.getLastAnnotation(Request.class)); 100 for (MethodInfo m : cm.getInfo().getAllMethods()) { 101 102 if (m.isPublic()) { 103 assertNoInvalidAnnotations(m, ResponseHeader.class, ResponseBody.class, ResponseStatus.class); 104 String n = m.getSimpleName(); 105 if (m.hasAnnotation(Header.class)) { 106 assertNoArgs(m, Header.class); 107 assertReturnNotVoid(m, Header.class); 108 properties.put(n, RequestBeanPropertyMeta.create(HEADER, Header.class, m)); 109 } else if (m.hasAnnotation(Query.class)) { 110 assertNoArgs(m, Query.class); 111 assertReturnNotVoid(m, Query.class); 112 properties.put(n, RequestBeanPropertyMeta.create(QUERY, Query.class, m)); 113 } else if (m.hasAnnotation(FormData.class)) { 114 assertNoArgs(m, FormData.class); 115 assertReturnNotVoid(m, FormData.class); 116 properties.put(n, RequestBeanPropertyMeta.create(FORMDATA, FormData.class, m)); 117 } else if (m.hasAnnotation(Path.class)) { 118 assertNoArgs(m, Path.class); 119 assertReturnNotVoid(m, Path.class); 120 properties.put(n, RequestBeanPropertyMeta.create(PATH, Path.class, m)); 121 } else if (m.hasAnnotation(Body.class)) { 122 assertNoArgs(m, Body.class); 123 assertReturnNotVoid(m, Body.class); 124 properties.put(n, RequestBeanPropertyMeta.create(BODY, Body.class, m)); 125 } 126 } 127 } 128 return this; 129 } 130 131 Builder apply(Request a) { 132 if (a != null) { 133 if (a.serializer() != HttpPartSerializer.Null.class) 134 serializer = a.serializer(); 135 if (a.parser() != HttpPartParser.Null.class) 136 parser = a.parser(); 137 } 138 return this; 139 } 140 141 RequestBeanMeta build() { 142 return new RequestBeanMeta(this); 143 } 144 } 145 146 /** 147 * Returns metadata about the class. 148 * 149 * @return Metadata about the class. 150 */ 151 public ClassMeta<?> getClassMeta() { 152 return cm; 153 } 154 155 /** 156 * Returns metadata about the bean property with the specified property name. 157 * 158 * @param name The bean property name. 159 * @return Metadata about the bean property, or <jk>null</jk> if none found. 160 */ 161 public RequestBeanPropertyMeta getProperty(String name) { 162 return properties.get(name); 163 } 164 165 /** 166 * Returns all the annotated methods on this bean. 167 * 168 * @return All the annotated methods on this bean. 169 */ 170 public Collection<RequestBeanPropertyMeta> getProperties() { 171 return properties.values(); 172 } 173}