/*
 * Copyright 2019 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.template.soy.data;

import java.lang.reflect.Method;

/** Reflective utilities related to {@link SoyTemplate}. */
public final class SoyTemplates {

  private SoyTemplates() {}

  /**
   * Reflectively obtains the default instance of a template type.
   *
   * @throws IllegalArgumentException if the template has one or more required parameters (i.e. the
   *     getDefaultInstance method does not exist on the class).
   */
  public static <T extends SoyTemplate> T getDefaultInstance(Class<T> type) {
    try {
      Method factory = type.getDeclaredMethod("getDefaultInstance");
      Object instance = factory.invoke(null);
      return type.cast(instance);
    } catch (NoSuchMethodException e) {
      throw new IllegalArgumentException(
          "No default instance for template type " + type.getName(), e);
    } catch (ReflectiveOperationException e) {
      throw new RuntimeException(
          "Unexpected error while calling getDefaultInstance() on " + type.getName(), e);
    }
  }

  /** Reflectively creates a builder of a template type. */
  public static <T extends SoyTemplate> SoyTemplate.Builder<T> getBuilder(Class<T> type) {
    try {
      Method factory = type.getDeclaredMethod("builder");
      @SuppressWarnings("unchecked")
      SoyTemplate.Builder<T> instance = (SoyTemplate.Builder<T>) factory.invoke(null);
      return instance;
    } catch (ReflectiveOperationException e) {
      throw new RuntimeException(
          "Unexpected error while calling builder() on " + type.getName(), e);
    }
  }
}

@@ -628,16 +628,48 @@
 .data;%0A%0A
+import java.lang.reflect.Field;%0A
 import j
@@ -2176,11 +2176,795 @@
    %7D%0A  %7D
+%0A%0A  private static final ClassValue%3CString%3E templateNameValue =%0A      new ClassValue%3CString%3E() %7B%0A        @Override%0A        protected String computeValue(Class%3C?%3E type) %7B%0A          try %7B%0A            Field field = type.getDeclaredField(%22__NAME__%22);%0A            field.setAccessible(true); // the field is private%0A            return (String) field.get(null);%0A          %7D catch (ReflectiveOperationException e) %7B%0A            throw new IllegalStateException(%0A                %22Unexpected error while accessing the template name of %22 + type.getName(), e);%0A          %7D%0A        %7D%0A      %7D;%0A%0A  /** Returns the name of the Soy template that this template class would render. */%0A  public static String getTemplateName(Class%3C? extends SoyTemplate%3E type) %7B%0A    return templateNameValue.get(type);%0A  %7D
 %0A%7D%0A

Create a restricted mechanism way to query the template name from a builder class.