/* * Copyright 2001-2013 Stephen Colebourne * * 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.joda.beans.ui.form; import java.lang.annotation.Annotation; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Objects; import javax.validation.constraints.DecimalMax; import javax.validation.constraints.DecimalMin; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.joda.beans.MetaBean; import org.joda.beans.MetaProperty; import org.joda.beans.PropertyDefinition; import org.joda.beans.PropertyStyle; /** * Factory used to create {@code MetaUIForm} instances. * <p> * This class is designed to be subclassed. */ public class MetaUIFactory { /** * Creates an instance. */ public MetaUIFactory() { } //------------------------------------------------------------------------- /** * Creates a form for a meta-bean. * * @param metaBean the meta-bean, not null * @return the form, not null */ public MetaUIForm createForm(final MetaBean metaBean) { Objects.requireNonNull(metaBean, "metaBean"); MetaUIForm form = createEmptyMetaForm(metaBean); for (MetaProperty<?> mp : metaBean.metaPropertyIterable()) { buildComponent(form, mp); } return form; } /** * Creates an empty form. * * @param metaBean the meta-bean, not null * @return the empty form, not null */ protected MetaUIForm createEmptyMetaForm(final MetaBean metaBean) { return new MetaUIForm(metaBean); } /** * Builds the component for the property. * * @param form the form to add to, not null * @param mp the meta-property, not null */ protected void buildComponent(MetaUIForm form, MetaProperty<?> mp) { MetaUIComponent comp = createEmptyMetaComponent(mp); buildReadOnly(comp); buildMandatory(comp); buildMinMax(comp); buildSize(comp); buildValues(comp); form.getComponents().add(comp); } /** * Creates an empty component. * * @param metaProperty the meta-property, not null * @return the empty component, not null */ protected MetaUIComponent createEmptyMetaComponent(MetaProperty<?> metaProperty) { return new MetaUIComponent(metaProperty); } /** * Builds the mandatory flag for the component. * * @param comp the component, not null */ protected void buildReadOnly(MetaUIComponent comp) { PropertyStyle style = comp.getMetaProperty().style(); if (style == PropertyStyle.DERIVED || style == PropertyStyle.READ_ONLY) { comp.setReadOnly(true); } } /** * Builds the mandatory flag for the component. * * @param comp the component, not null */ protected void buildMandatory(MetaUIComponent comp) { if (comp.getMetaProperty().propertyType().isPrimitive()) { comp.setMandatory(true); } PropertyDefinition propAnno = findAnnotation(comp, PropertyDefinition.class); if (propAnno != null) { if (propAnno.validate().equals("notNull") || propAnno.validate().equals("notEmpty")) { comp.setMandatory(true); } } NotNull nnAnno = findAnnotation(comp, NotNull.class); if (nnAnno != null) { comp.setMandatory(true); } } /** * Builds the min/max values for the component. * * @param comp the component, not null */ protected void buildMinMax(MetaUIComponent comp) { DecimalMax dmaxAnno = findAnnotation(comp, DecimalMax.class); DecimalMin dminAnno = findAnnotation(comp, DecimalMin.class); Max maxAnno = findAnnotation(comp, Max.class); Min minAnno = findAnnotation(comp, Min.class); if (dminAnno != null) { comp.setMinValue(new BigDecimal(dminAnno.value())); } else if (minAnno != null) { comp.setMinValue(minAnno.value()); } if (dmaxAnno != null) { comp.setMaxValue(new BigDecimal(dmaxAnno.value())); } else if (maxAnno != null) { comp.setMaxValue(maxAnno.value()); } } /** * Builds the min/max size for the component. * * @param comp the component, not null */ protected void buildSize(MetaUIComponent comp) { Size sizeAnno = findAnnotation(comp, Size.class); if (sizeAnno != null) { comp.setMinSize(sizeAnno.min()); comp.setMaxSize(sizeAnno.max()); } } /** * Builds the selectable values for the component. * * @param comp the component, not null */ protected void buildValues(MetaUIComponent comp) { Class<?> type = comp.getMetaProperty().propertyType(); if (Enum.class.isAssignableFrom(type)) { Object[] values = type.getEnumConstants(); comp.setLimitedValues(true); comp.setSelectableValues(new ArrayList<>(Arrays.asList(values))); } } //------------------------------------------------------------------------- /** * Finds an annotation on the property, returning null if not found. * * @param <A> the annotation type * @param metaComponent the meta-component to examine, not null * @param annotationType the annotation type, not null * @return the annotation, null if not found */ protected <A extends Annotation> A findAnnotation(MetaUIComponent metaComponent, Class<A> annotationType) { try { return metaComponent.getMetaProperty().annotation(annotationType); } catch (RuntimeException ex) { return null; } } }