2021SC@SDUSC
jsp包
FreemarkerTag.java
代码分析
package freemarker.ext.jsp;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.Tag;
import freemarker.template.Configuration;
import freemarker.template.SimpleHash;
import freemarker.template.Template;
/**
* 允许FreeMarker在JSP中使用模板的JSP标签
*/
@Deprecated
public class FreemarkerTag implements BodyTag {
private Tag parent;
private BodyContent bodyContent;
private PageContext pageContext;
private SimpleHash root;
private Template template;
private boolean caching = true;
private String name = "";
public boolean getCaching() {
return caching;
}
public void setCaching(boolean caching) {
this.caching = caching;
}
public void setName(String name) {
this.name = name == null ? "" : name;
}
@Override
public Tag getParent() {
return parent;
}
@Override
public void setParent(Tag parent) {
this.parent = parent;
}
@Override
public int doStartTag() {
return EVAL_BODY_BUFFERED;
}
@Override
public void setBodyContent(BodyContent bodyContent) {
this.bodyContent = bodyContent;
}
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
root = null;
}
@Override
public void doInitBody() {
}
@Override
public int doAfterBody() {
return SKIP_BODY;
}
@Override
public void release() {
root = null;
template = null;
name = "";
}
@Override
public int doEndTag()
throws JspException {
if (bodyContent == null)
return EVAL_PAGE;
try {
if (template == null) {
template = new Template(name, bodyContent.getReader());
}
if (root == null) {
root = new SimpleHash();
root.put("page", new JspContextModel(pageContext, JspContextModel.PAGE_SCOPE));
root.put("request", new JspContextModel(pageContext, JspContextModel.REQUEST_SCOPE));
root.put("session", new JspContextModel(pageContext, JspContextModel.SESSION_SCOPE));
root.put("application", new JspContextModel(pageContext, JspContextModel.APPLICATION_SCOPE));
root.put("any", new JspContextModel(pageContext, JspContextModel.ANY_SCOPE));
}
template.process(root, pageContext.getOut());
} catch (Exception e) {
try {
pageContext.handlePageException(e);
} catch (ServletException | IOException e2) {
throw new JspException(e2.getMessage());
}
} finally {
if (!caching) {
template = null;
}
}
return EVAL_PAGE;
}
}
JspContextModel.java
代码分析
package freemarker.ext.jsp;
import javax.servlet.jsp.PageContext;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
/**
* @Deprecated 该类被用于装饰 {@link FreemarkerTag}.
*/
@Deprecated
class JspContextModel
implements
TemplateHashModel {
public static final int ANY_SCOPE = -1;
public static final int PAGE_SCOPE = PageContext.PAGE_SCOPE;
public static final int REQUEST_SCOPE = PageContext.REQUEST_SCOPE;
public static final int SESSION_SCOPE = PageContext.SESSION_SCOPE;
public static final int APPLICATION_SCOPE = PageContext.APPLICATION_SCOPE;
private final PageContext pageContext;
private final int scope;
public JspContextModel(PageContext pageContext, int scope) {
this.pageContext = pageContext;
this.scope = scope;
}
@Override
public TemplateModel get(String key) throws TemplateModelException {
Object bean = scope == ANY_SCOPE ? pageContext.findAttribute(key) : pageContext.getAttribute(key, scope);
return BeansWrapper.getDefaultInstance().wrap(bean);
}
@Override
public boolean isEmpty() {
return false;
}
}
JspTagModelBase.java
代码分析
package freemarker.ext.jsp;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import freemarker.core._DelayedJQuote;
import freemarker.core._DelayedShortClassName;
import freemarker.core._ErrorDescriptionBuilder;
import freemarker.core._TemplateModelException;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.jsp.SimpleTagDirectiveModel.TemplateExceptionWrapperJspException;
import freemarker.template.ObjectWrapper;
import freemarker.template.ObjectWrapperAndUnwrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.utility.StringUtil;
class JspTagModelBase {
protected final String tagName;
private final Class tagClass;
private final Method dynaSetter;
private final Map propertySetters = new HashMap();
protected JspTagModelBase(String tagName, Class tagClass) throws IntrospectionException {
this.tagName = tagName;
this.tagClass = tagClass;
BeanInfo bi = Introspector.getBeanInfo(tagClass);
PropertyDescriptor[] pda = bi.getPropertyDescriptors();
for (int i = 0; i < pda.length; i++) {
PropertyDescriptor pd = pda[i];
Method m = pd.getWriteMethod();
if (m != null) {
propertySetters.put(pd.getName(), m);
}
}
// 判断这个标签(tag)是否实现了JSP2.0 的动态属性,接口,
以便允许使用任意属性,方法
Method dynaSetter;
try {
dynaSetter = tagClass.getMethod("setDynamicAttribute",
new Class[] {String.class, String.class, Object.class});
} catch (NoSuchMethodException nsme) {
dynaSetter = null;
}
this.dynaSetter = dynaSetter;
}
Object getTagInstance() throws IllegalAccessException, InstantiationException {
return tagClass.newInstance();
}
void setupTag(Object tag, Map args, ObjectWrapper wrapper)
throws TemplateModelException,
InvocationTargetException,
IllegalAccessException {
if (args != null && !args.isEmpty()) {
ObjectWrapperAndUnwrapper unwrapper =
wrapper instanceof ObjectWrapperAndUnwrapper ? (ObjectWrapperAndUnwrapper) wrapper
: BeansWrapper.getDefaultInstance(); // [2.4] Throw exception in this case
final Object[] argArray = new Object[1];
for (Iterator iter = args.entrySet().iterator(); iter.hasNext(); ) {
final Map.Entry entry = (Map.Entry) iter.next();
final Object arg = unwrapper.unwrap((TemplateModel) entry.getValue());
argArray[0] = arg;
final Object paramName = entry.getKey();
Method setterMethod = (Method) propertySetters.get(paramName);
if (setterMethod == null) {
if (dynaSetter == null) {
throw new TemplateModelException("Unknown property "
+ StringUtil.jQuote(paramName.toString())
+ " on instance of " + tagClass.getName());
} else {
dynaSetter.invoke(tag, null, paramName, argArray[0]);
}
} else {
if (arg instanceof BigDecimal) {
argArray[0] = BeansWrapper.coerceBigDecimal(
(BigDecimal) arg, setterMethod.getParameterTypes()[0]);
}
try {
setterMethod.invoke(tag, argArray);
} catch (Exception e) {
final Class setterType = setterMethod.getParameterTypes()[0];
final _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder(
"Failed to set JSP tag parameter ", new _DelayedJQuote(paramName),
" (declared type: ", new _DelayedShortClassName(setterType)
+ ", actual value's type: ",
(argArray[0] != null
? new _DelayedShortClassName(argArray[0].getClass()) : "Null"),
"). See cause exception for the more specific cause...");
if (e instanceof IllegalArgumentException && !(setterType.isAssignableFrom(String.class))
&& argArray[0] != null && argArray[0] instanceof String) {
desc.tip("This problem is often caused by unnecessary parameter quotation. Paramters "
+ "aren't quoted in FTL, similarly as they aren't quoted in most languages. "
+ "For example, these parameter assignments are wrong: ",
"<@my.tag p1=\"true\" p2=\"10\" p3=\"${someVariable}\" p4=\"${x+1}\" />",
". The correct form is: ",
"<@my.tag p1=true p2=10 p3=someVariable p4=x+1 />",
". Only string literals are quoted (regardless of where they occur): ",
"<@my.box style=\"info\" message=\"Hello ${name}!\" width=200 />",
".");
}
throw new _TemplateModelException(e, null, desc);
}
}
}
}
}
protected final TemplateModelException toTemplateModelExceptionOrRethrow(Exception e) throws TemplateModelException {
if (e instanceof RuntimeException && !isCommonRuntimeException((RuntimeException) e)) {
throw (RuntimeException) e;
}
if (e instanceof TemplateModelException) {
throw (TemplateModelException) e;
}
if (e instanceof TemplateExceptionWrapperJspException) {
return toTemplateModelExceptionOrRethrow(((TemplateExceptionWrapperJspException) e).getCause());
}
return new TemplateModelException(
"Error while invoking the " + StringUtil.jQuote(tagName) + " JSP custom tag; see cause exception",
e instanceof TemplateException, e);
}
/**
* Runtime exceptions that we don't want to propagate, instead we warp them into a more helpful exception. These are
* the ones where it's very unlikely that someone tries to catch specifically these around
* {@link Template#process(Object, java.io.Writer)}.
*/
private boolean isCommonRuntimeException(RuntimeException e) {
final Class eClass = e.getClass();
// We deliberately don't accept sub-classes. Those are possibly application specific and some want to catch them
// outside the template.
return eClass == NullPointerException.class
|| eClass == IllegalArgumentException.class
|| eClass == ClassCastException.class
|| eClass == IndexOutOfBoundsException.class;
}
}
JspWriterAdapter.java
代码分析
package freemarker.ext.jsp;
import java.io.IOException;
import java.io.Writer;
import javax.servlet.jsp.JspWriter;
import freemarker.template.utility.SecurityUtilities;
class JspWriterAdapter extends JspWriter {
static final char[] NEWLINE = SecurityUtilities.getSystemProperty("line.separator", "\n").toCharArray();
private final Writer out;
JspWriterAdapter(Writer out) {
super(0, true);
this.out = out;
}
@Override
public String toString() {
return "JspWriterAdapter wrapping a " + out.toString();
}
@Override
public void clear() throws IOException {
throw new IOException("Can't clear");
}
@Override
public void clearBuffer() throws IOException {
throw new IOException("Can't clear");
}
@Override
public void close() throws IOException {
throw new IOException("Close not permitted.");
}
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public int getRemaining() {
return 0;
}
@Override
public void newLine() throws IOException {
out.write(NEWLINE);
}
@Override
public void print(boolean arg0) throws IOException {
out.write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
}
@Override
public void print(char arg0) throws IOException {
out.write(arg0);
}
@Override
public void print(char[] arg0) throws IOException {
out.write(arg0);
}
@Override
public void print(double arg0) throws IOException {
out.write(Double.toString(arg0));
}
@Override
public void print(float arg0) throws IOException {
out.write(Float.toString(arg0));
}
@Override
public void print(int arg0) throws IOException {
out.write(Integer.toString(arg0));
}
@Override
public void print(long arg0) throws IOException {
out.write(Long.toString(arg0));
}
@Override
public void print(Object arg0) throws IOException {
out.write(arg0 == null ? "null" : arg0.toString());
}
@Override
public void print(String arg0) throws IOException {
out.write(arg0);
}
@Override
public void println() throws IOException {
newLine();
}
@Override
public void println(boolean arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(char arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(char[] arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(double arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(float arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(int arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(long arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(Object arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void println(String arg0) throws IOException {
print(arg0);
newLine();
}
@Override
public void write(int c) throws IOException {
out.write(c);
}
@Override
public void write(char[] arg0, int arg1, int arg2)
throws IOException {
out.write(arg0, arg1, arg2);
}
}
|