001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.tags.form; 018 019import java.util.Collection; 020import javax.servlet.jsp.JspException; 021 022import org.springframework.web.bind.WebDataBinder; 023 024/** 025 * Databinding-aware JSP tag for rendering an HTML '{@code input}' 026 * element with a '{@code type}' of '{@code checkbox}'. 027 * 028 * <p>May be used in one of three different approaches depending on the 029 * type of the {@link #getValue bound value}. 030 * 031 * <h3>Approach One</h3> 032 * When the bound value is of type {@link Boolean} then the '{@code input(checkbox)}' 033 * is marked as 'checked' if the bound value is {@code true}. The '{@code value}' 034 * attribute corresponds to the resolved value of the {@link #setValue(Object) value} property. 035 * <h3>Approach Two</h3> 036 * When the bound value is of type {@link Collection} then the '{@code input(checkbox)}' 037 * is marked as 'checked' if the configured {@link #setValue(Object) value} is present in 038 * the bound {@link Collection}. 039 * <h3>Approach Three</h3> 040 * For any other bound value type, the '{@code input(checkbox)}' is marked as 'checked' 041 * if the configured {@link #setValue(Object) value} is equal to the bound value. 042 * 043 * @author Rob Harrop 044 * @author Juergen Hoeller 045 * @since 2.0 046 */ 047@SuppressWarnings("serial") 048public class CheckboxTag extends AbstractSingleCheckedElementTag { 049 050 @Override 051 protected int writeTagContent(TagWriter tagWriter) throws JspException { 052 super.writeTagContent(tagWriter); 053 054 if (!isDisabled()) { 055 // Write out the 'field was present' marker. 056 tagWriter.startTag("input"); 057 tagWriter.writeAttribute("type", "hidden"); 058 String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName(); 059 tagWriter.writeAttribute("name", name); 060 tagWriter.writeAttribute("value", processFieldValue(name, "on", "hidden")); 061 tagWriter.endTag(); 062 } 063 064 return SKIP_BODY; 065 } 066 067 @Override 068 protected void writeTagDetails(TagWriter tagWriter) throws JspException { 069 tagWriter.writeAttribute("type", getInputType()); 070 071 Object boundValue = getBoundValue(); 072 Class<?> valueType = getBindStatus().getValueType(); 073 074 if (Boolean.class == valueType || boolean.class == valueType) { 075 // the concrete type may not be a Boolean - can be String 076 if (boundValue instanceof String) { 077 boundValue = Boolean.valueOf((String) boundValue); 078 } 079 Boolean booleanValue = (boundValue != null ? (Boolean) boundValue : Boolean.FALSE); 080 renderFromBoolean(booleanValue, tagWriter); 081 } 082 083 else { 084 Object value = getValue(); 085 if (value == null) { 086 throw new IllegalArgumentException("Attribute 'value' is required when binding to non-boolean values"); 087 } 088 Object resolvedValue = (value instanceof String ? evaluate("value", value) : value); 089 renderFromValue(resolvedValue, tagWriter); 090 } 091 } 092 093 @Override 094 protected String getInputType() { 095 return "checkbox"; 096 } 097 098}