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.commons.utils.CollectionUtils.*;
020import static org.apache.juneau.commons.utils.Shorts.*;
021
022import java.lang.annotation.*;
023import java.lang.reflect.*;
024import java.util.*;
025
026import org.apache.juneau.commons.*;
027import org.apache.juneau.commons.httppart.*;
028import org.apache.juneau.commons.inject.*;
029import org.apache.juneau.commons.reflect.*;
030import org.apache.juneau.http.*;
031import org.apache.juneau.marshall.httppart.*;
032
033/**
034 * Represents the metadata gathered from a getter method of a 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 RequestBeanPropertyMeta {
041
042   private static final AnnotationProvider AP = AnnotationProvider.INSTANCE;
043
044   static class Builder {
045      HttpPartType partType;
046      HttpPartSchema schema;
047      Method getter;
048
049      RequestBeanPropertyMeta build(HttpPartSerializer serializer, HttpPartParser parser) {
050         return new RequestBeanPropertyMeta(this, serializer, parser);
051      }
052
053      Builder getter(Method value) {
054         getter = value;
055         return this;
056      }
057
058      Builder partType(HttpPartType value) {
059         partType = value;
060         return this;
061      }
062
063      Builder schema(HttpPartSchema value) {
064         schema = value;
065         return this;
066      }
067   }
068
069   static RequestBeanPropertyMeta.Builder create(HttpPartType partType, Class<? extends Annotation> c, MethodInfo m) {
070      var sb = HttpPartSchema.create().name(m.getPropertyName());
071      var ap = AP;
072      rstream(ap.find(Schema.class, m)).forEach(x -> sb.apply(x.inner()));
073      rstream(ap.find(c, m)).forEach(x -> sb.apply(x.inner()));
074      return new Builder().partType(partType).schema(sb.build()).getter(m.inner());
075   }
076
077   private final Method getter;
078   private final HttpPartType partType;
079   private final Optional<HttpPartSerializer> serializer;
080   private final HttpPartParser parser;
081
082   private final HttpPartSchema schema;
083
084   @SuppressWarnings({
085      "unchecked" // Type erasure on reflective/generic cast; element type is verified at call site
086   })
087   RequestBeanPropertyMeta(Builder b, HttpPartSerializer serializer, HttpPartParser parser) {
088      partType = b.partType;
089      schema = b.schema;
090      getter = b.getter;
091      this.serializer = o(BeanInstantiator.createOrDefault((Class<HttpPartSerializer>) schema.getSerializer(), serializer));
092      this.parser = BeanInstantiator.createOrDefault((Class<HttpPartParser>) schema.getParser(), parser);
093   }
094
095   /**
096    * Returns the name of the Java method getter that defines this property.
097    *
098    * @return
099    *    The name of the Java method getter that defines this property.
100    *    <br>Never <jk>null</jk>.
101    */
102   public Method getGetter() { return getter; }
103
104   /**
105    * Returns the parser to use for parsing the bean property value.
106    *
107    * @param defaultParser The default parser to use if not defined on the annotation. Can be <jk>null</jk>.
108    * @return
109    *    The parser to use for parsing the bean property value, or <c>defaultParser</c> (which can be <jk>null</jk>)
110    *    if no parser is configured on the annotation.
111    */
112   public HttpPartParserSession getParser(HttpPartParserSession defaultParser) {
113      return parser == null ? defaultParser : parser.getPartSession();
114   }
115
116   /**
117    * Returns the HTTP part name for this property (query parameter name for example).
118    *
119    * @return The HTTP part name, or <jk>null</jk> if it doesn't have a part name.
120    */
121   public String getPartName() { return schema.getName(); }
122
123   /**
124    * Returns the HTTP part type for this property (query parameter for example).
125    *
126    * @return
127    *    The HTTP part type for this property.
128    *    <br>Never <jk>null</jk>.
129    */
130   public HttpPartType getPartType() { return partType; }
131
132   /**
133    * Returns the schema information gathered from annotations on the method and return type.
134    *
135    * @return
136    *    The schema information gathered from annotations on the method and return type.
137    *    <br>Never <jk>null</jk>.
138    */
139   public HttpPartSchema getSchema() { return schema; }
140
141   /**
142    * Returns the serializer to use for serializing the bean property value.
143    *
144    * @return The serializer to use for serializing the bean property value.
145    */
146   public Optional<HttpPartSerializer> getSerializer() { return serializer; }
147}