/* * Copyright 2015 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.jbcsrc.shared; import static com.google.common.base.Preconditions.checkArgument; import com.google.template.soy.base.internal.BaseUtils; /** * Utilities for translating soy symbols to and from strings that are suitable for use in java class * files. These utilities are shared between the compiler and the runtime system. */ public final class Names { public static final String CLASS_PREFIX = "com.google.template.soy.jbcsrc.gen."; public static final String INTERNAL_CLASS_PREFIX = CLASS_PREFIX.replace('.', '/'); private Names() {} /** * Translate a user controlled Soy name to a form that is safe to encode in a java class, method * or field name. * * <p>Soy identifiers are very simple, they are restricted to the following regex: {@code * [a-zA-Z_]([a-zA-Z_0-9])*}. So a template name is just one or more identifiers separated by * {@code .} characters. To escape it, we simply replace all '.'s with '_'s, and all '_'s with * '__' and prefix with a package name. */ public static String javaClassNameFromSoyTemplateName(String soyTemplate) { checkArgument( BaseUtils.isDottedIdentifier(soyTemplate), "%s is not a valid template name.", soyTemplate); return CLASS_PREFIX + soyTemplate; } /** * Given the soy namespace and file name returns the path where the corresponding resource should * be stored. */ public static String javaFileName(String soyNamespace, String fileName) { checkArgument( BaseUtils.isDottedIdentifier(soyNamespace), "%s is not a valid soy namspace name.", soyNamespace); return (CLASS_PREFIX + soyNamespace).replace('.', '/') + '/' + fileName; } /** * Translates a Java class name generated by {@link #javaClassNameFromSoyTemplateName}, back to * the original soy template name. */ public static String soyTemplateNameFromJavaClassName(String javaClass) { if (!javaClass.startsWith(CLASS_PREFIX)) { throw new IllegalArgumentException( "java class: " + javaClass + " is not a mangled soy template name"); } return javaClass.substring(CLASS_PREFIX.length()); } /** * Rewrites the given stack trace by replacing all references to generated jbcsrc types with the * original template names. */ public static void rewriteStackTrace(Throwable throwable) { StackTraceElement[] stack = throwable.getStackTrace(); for (int i = 0; i < stack.length; i++) { StackTraceElement curr = stack[i]; if (curr.getClassName().startsWith(CLASS_PREFIX)) { stack[i] = new StackTraceElement( soyTemplateNameFromJavaClassName(curr.getClassName()), // TODO(lukes): remove the method name? only if it == 'render'? curr.getMethodName(), curr.getFileName(), curr.getLineNumber()); } } throwable.setStackTrace(stack); } }