aboutsummaryrefslogtreecommitdiff
path: root/gson/src/main/java/com/google/gson/internal/reflect/ReflectionHelper.java
blob: 97230ff6f503609164ec7e0d6cbcbe7edf6e87e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.google.gson.internal.reflect;

import com.google.gson.JsonIOException;
import com.google.gson.internal.GsonBuildConfig;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class ReflectionHelper {
  private ReflectionHelper() { }

  /**
   * Tries making the field accessible, wrapping any thrown exception in a
   * {@link JsonIOException} with descriptive message.
   *
   * @param field field to make accessible
   * @throws JsonIOException if making the field accessible fails
   */
  public static void makeAccessible(Field field) throws JsonIOException {
    try {
      field.setAccessible(true);
    } catch (Exception exception) {
      throw new JsonIOException("Failed making field '" + field.getDeclaringClass().getName() + "#"
          + field.getName() + "' accessible; either change its visibility or write a custom "
          + "TypeAdapter for its declaring type", exception);
    }
  }

  /**
   * Creates a string representation for a constructor.
   * E.g.: {@code java.lang.String#String(char[], int, int)}
   */
  private static String constructorToString(Constructor<?> constructor) {
    StringBuilder stringBuilder = new StringBuilder(constructor.getDeclaringClass().getName())
      .append('#')
      .append(constructor.getDeclaringClass().getSimpleName())
      .append('(');
    Class<?>[] parameters = constructor.getParameterTypes();
    for (int i = 0; i < parameters.length; i++) {
      if (i > 0) {
        stringBuilder.append(", ");
      }
      stringBuilder.append(parameters[i].getSimpleName());
    }

    return stringBuilder.append(')').toString();
  }

  /**
   * Tries making the constructor accessible, returning an exception message
   * if this fails.
   *
   * @param constructor constructor to make accessible
   * @return exception message; {@code null} if successful, non-{@code null} if
   *    unsuccessful
   */
  public static String tryMakeAccessible(Constructor<?> constructor) {
    try {
      constructor.setAccessible(true);
      return null;
    } catch (Exception exception) {
      return "Failed making constructor '" + constructorToString(constructor) + "' accessible; "
          + "either change its visibility or write a custom InstanceCreator or TypeAdapter for its declaring type: "
          // Include the message since it might contain more detailed information
          + exception.getMessage();
    }
  }

  public static RuntimeException createExceptionForUnexpectedIllegalAccess(IllegalAccessException exception) {
    throw new RuntimeException("Unexpected IllegalAccessException occurred (Gson " + GsonBuildConfig.VERSION + "). "
        + "Certain ReflectionAccessFilter features require Java >= 9 to work correctly. If you are not using "
        + "ReflectionAccessFilter, report this to the Gson maintainers.",
        exception);
  }
}