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.commons.reflect;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.ClassUtils.*;
021
022import java.beans.beancontext.*;
023import java.lang.reflect.*;
024
025/**
026 * Defines class/field/method visibilities.
027 *
028 * <p>
029 * Used to specify minimum levels of visibility when detecting bean classes, methods, and fields.
030 *
031 * <p>
032 * Used in conjunction with the following bean context properties:
033 * <ul class='javatree'>
034 *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanConstructorVisibility}
035 *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanClassVisibility}
036 *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanFieldVisibility}
037 *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#beanMethodVisibility}
038 * </ul>
039 *
040 */
041public enum Visibility {
042
043   /** Ignore all */
044   NONE,
045
046   /** Include only <jk>public</jk> classes/fields/methods. */
047   PUBLIC,
048
049   /** Include only <jk>public</jk> or <jk>protected</jk> classes/fields/methods. */
050   PROTECTED,
051
052   /** Include all but <jk>private</jk> classes/fields/methods. */
053   DEFAULT,
054
055   /** Include all classes/fields/methods. */
056   PRIVATE;
057
058   /**
059    * Shortcut for <c>isVisible(x.getModifiers());</c>
060    *
061    * @param x The class to check.
062    * @return <jk>true</jk> if the class is at least as visible as this object.
063    */
064   public boolean isVisible(Class<?> x) {
065      return isVisible(x.getModifiers());
066   }
067
068   /**
069    * Shortcut for <c>isVisible(x.getModifiers());</c>
070    *
071    * @param x The constructor to check.
072    * @return <jk>true</jk> if the constructor is at least as visible as this object.
073    */
074   public boolean isVisible(Executable x) {
075      return isVisible(x.getModifiers());
076   }
077
078   /**
079    * Shortcut for <c>isVisible(x.getModifiers());</c>
080    *
081    * @param x The field to check.
082    * @return <jk>true</jk> if the field is at least as visible as this object.
083    */
084   public boolean isVisible(Field x) {
085      return isVisible(x.getModifiers());
086   }
087
088   /**
089    * Identifies if the specified mod matches this visibility.
090    *
091    * <h5 class='section'>Example:</h5>
092    * <p class='bjava'>
093    *    <jsf>PUBLIC</jsf>.isVisible(MyPublicClass.<jk>class</jk>.getModifiers()); <jc>//true</jc>
094    *    <jsf>PUBLIC</jsf>.isVisible(MyPrivateClass.<jk>class</jk>.getModifiers()); <jc>//false</jc>
095    *    <jsf>PRIVATE</jsf>.isVisible(MyPrivateClass.<jk>class</jk>.getModifiers()); <jc>//true</jc>
096    *    <jsf>NONE</jsf>.isVisible(MyPublicClass.<jk>class</jk>.getModifiers()); <jc>//false</jc>
097    * </p>
098    *
099    * @param mod The modifier from the object being tested (e.g. results from {@link Class#getModifiers()}.
100    * @return <jk>true</jk> if this visibility matches the specified modifier attribute.
101    */
102   public boolean isVisible(int mod) {
103      return switch (this) {
104         case NONE -> false;
105         case PRIVATE -> true;
106         case DEFAULT -> ! Modifier.isPrivate(mod);
107         case PROTECTED -> Modifier.isProtected(mod) || Modifier.isPublic(mod);
108         default -> Modifier.isPublic(mod);
109      };
110   }
111
112   /**
113    * Makes constructor accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
114    *
115    * <p>
116    * Security exceptions thrown on the call to {@link Constructor#setAccessible(boolean)} are quietly ignored.
117    *
118    * @param <T> The class type.
119    * @param x The constructor. Must not be <jk>null</jk>.
120    * @return
121    *    The same constructor if visibility requirements met, or <jk>null</jk> if visibility requirement not
122    *    met or call to {@link Constructor#setAccessible(boolean)} throws a security exception.
123    * @throws IllegalArgumentException If <c>x</c> is <jk>null</jk>.
124    */
125   public <T> Constructor<T> transform(Constructor<T> x) {
126      assertArgNotNull("x", x);
127      if (isVisible(x))
128         if (! setAccessible(x))
129            return null;  // HTT
130      return x;
131   }
132
133   /**
134    * Makes field accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
135    *
136    * <p>
137    * Security exceptions thrown on the call to {@link Field#setAccessible(boolean)} are quietly ignored.
138    *
139    * @param x The field. Must not be <jk>null</jk>.
140    * @return
141    *    The same field if visibility requirements met, or <jk>null</jk> if visibility requirement not
142    *    met or call to {@link Field#setAccessible(boolean)} throws a security exception.
143    * @throws IllegalArgumentException If <c>x</c> is <jk>null</jk>.
144    */
145   public Field transform(Field x) {
146      assertArgNotNull("x", x);
147      if (isVisible(x))
148         if (! setAccessible(x))
149            return null;  // HTT
150      return x;
151   }
152
153   /**
154    * Makes method accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
155    *
156    * <p>
157    * Security exceptions thrown on the call to {@link Method#setAccessible(boolean)} are quietly ignored.
158    *
159    * @param x The method. Must not be <jk>null</jk>.
160    * @return
161    *    The same method if visibility requirements met, or <jk>null</jk> if visibility requirement not
162    *    met or call to {@link Method#setAccessible(boolean)} throws a security exception.
163    * @throws IllegalArgumentException If <c>x</c> is <jk>null</jk>.
164    */
165   public Method transform(Method x) {
166      assertArgNotNull("x", x);
167      if (isVisible(x))
168         if (! setAccessible(x))
169            return null;  // HTT
170      return x;
171   }
172}