/* * ============================================================================= * * Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org) * * 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 org.thymeleaf.engine; import java.io.IOException; import java.io.Writer; import org.thymeleaf.exceptions.TemplateProcessingException; import org.thymeleaf.model.AttributeValueQuotes; import org.thymeleaf.model.IAttribute; import org.thymeleaf.standard.expression.IStandardExpression; import org.thymeleaf.util.FastStringWriter; /* * Engine implementation of IAttribute. * * @author Daniel Fernandez * @since 3.0.0 */ final class Attribute implements IAttribute { static final String DEFAULT_OPERATOR = "="; /* * Note: An Attribute should not be made responsible for converting non-String values to String, or computing * the boolean-ness of attributes or their representation. All these should be the responsibility of the * diverse processors being executed. This class is a raw representation of what appears/will appear on template. */ final AttributeDefinition definition; final String completeName; final String operator; // can be null final String value; final AttributeValueQuotes valueQuotes; final String templateName; final int line; final int col; private volatile IStandardExpression standardExpression = null; Attribute( final AttributeDefinition definition, final String completeName, final String operator, final String value, final AttributeValueQuotes valueQuotes, final String templateName, final int line, final int col) { super(); this.definition = definition; this.completeName = completeName; this.value = value; if (value == null) { this.operator = null; } else { if (operator == null) { this.operator = DEFAULT_OPERATOR; } else { this.operator = operator; } } if (value == null) { // Null value will always have null quotes this.valueQuotes = null; } else { if (valueQuotes == null) { this.valueQuotes = AttributeValueQuotes.DOUBLE; } else if (valueQuotes == AttributeValueQuotes.NONE && value.length() == 0) { // We will not allow no quotes with the empty string this.valueQuotes = AttributeValueQuotes.DOUBLE; } else { this.valueQuotes = valueQuotes; } } this.templateName = templateName; this.line = line; this.col = col; } public AttributeDefinition getAttributeDefinition() { return this.definition; } public String getAttributeCompleteName() { return this.completeName; } public String getOperator() { return this.operator; } public String getValue() { return this.value; } public AttributeValueQuotes getValueQuotes() { return this.valueQuotes; } public String getTemplateName() { return this.templateName; } public final boolean hasLocation() { return (this.templateName != null && this.line != -1 && this.col != -1); } public int getLine() { return this.line; } public int getCol() { return this.col; } IStandardExpression getCachedStandardExpression() { return this.standardExpression; } void setCachedStandardExpression(final IStandardExpression standardExpression) { this.standardExpression = standardExpression; } /* * This method allows the easy creation of instances derivate from this one but keeping some specific fields */ Attribute modify( final AttributeDefinition definition, final String completeName, final String value, final AttributeValueQuotes valueQuotes) { return new Attribute( (definition == null? this.definition : definition), (completeName == null? this.completeName : completeName), this.operator, value, // This is not keepable (valueQuotes == null? this.valueQuotes : valueQuotes), this.templateName, this.line, this.col); } public void write(final Writer writer) throws IOException { /* * How an attribute will be written: * - If value == null : only the attribute name will be written. * - If value != null : the attribute will be written according to its quotes */ writer.write(this.completeName); if (this.value != null) { writer.write(this.operator); if (this.valueQuotes == null) { writer.write(this.value); } else { switch (this.valueQuotes) { case DOUBLE: writer.write('"'); writer.write(this.value); writer.write('"'); break; case SINGLE: writer.write('\''); writer.write(this.value); writer.write('\''); break; case NONE: writer.write(this.value); break; } } } } @Override public String toString() { final Writer stringWriter = new FastStringWriter(); try { write(stringWriter); } catch (final IOException e) { // Should never happen! throw new TemplateProcessingException("Error computing attribute representation", e); } return stringWriter.toString(); } }