// Path: example-app/example-app-widgetset/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/AttributeExtension.java
// @JavaScript("attribute_extension_connector.js")
// public class AttributeExtension extends AbstractJavaScriptExtension {
// 
//     public void extend(TextField target) {
//         super.extend(target);
//     }
// 
//     @Override
//     protected AttributeExtensionState getState() {
//         return (AttributeExtensionState) super.getState();
//     }
// 
//     public void setAttribute(String attribute, String value) {
//         getState().attributes.put(attribute, value);
//     }
// }
// 
// Path: example-app/example-app-backend/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/backend/data/Availability.java
// public enum Availability {
//     COMING("Coming"), AVAILABLE("Available"), DISCONTINUED("Discontinued");
// 
//     private final String name;
// 
//     private Availability(String name) {
//         this.name = name;
//     }
// 
//     @Override
//     public String toString() {
//         return name;
//     }
// }
// 
// Path: example-app/example-app-backend/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/backend/data/Category.java
// public class Category implements Serializable {
// 
//     @NotNull
//     private int id;
//     @NotNull
//     private String name;
// 
//     public int getId() {
//         return id;
//     }
// 
//     public void setId(int id) {
//         this.id = id;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public void setName(String name) {
//         this.name = name;
//     }
// 
//     @Override
//     public String toString() {
//         return getName();
//     }
// }
// 
// Path: example-app/example-app-backend/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/backend/data/Product.java
// public class Product implements Serializable {
// 
//     @NotNull
//     private int id = -1;
//     @NotNull
//     @Size(min = 2, message = "Product name must have at least two characters")
//     private String productName = "";
//     @Min(0)
//     private BigDecimal price = BigDecimal.ZERO;
//     private Set<Category> category;
//     @Min(value = 0, message = "Can't have negative amount in stock")
//     private int stockCount = 0;
//     @NotNull
//     private Availability availability = Availability.COMING;
// 
//     public int getId() {
//         return id;
//     }
// 
//     public void setId(int id) {
//         this.id = id;
//     }
// 
//     public String getProductName() {
//         return productName;
//     }
// 
//     public void setProductName(String productName) {
//         this.productName = productName;
//     }
// 
//     public BigDecimal getPrice() {
//         return price;
//     }
// 
//     public void setPrice(BigDecimal price) {
//         this.price = price;
//     }
// 
//     public Set<Category> getCategory() {
//         return category;
//     }
// 
//     public void setCategory(Set<Category> category) {
//         this.category = category;
//     }
// 
//     public int getStockCount() {
//         return stockCount;
//     }
// 
//     public void setStockCount(int stockCount) {
//         this.stockCount = stockCount;
//     }
// 
//     public Availability getAvailability() {
//         return availability;
//     }
// 
//     public void setAvailability(Availability availability) {
//         this.availability = availability;
//     }
// 
// }


import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Locale;
import com.github.mcollovati.vaadin.exampleapp.samples.AttributeExtension;
import com.github.mcollovati.vaadin.exampleapp.samples.backend.data.Availability;
import com.github.mcollovati.vaadin.exampleapp.samples.backend.data.Category;
import com.github.mcollovati.vaadin.exampleapp.samples.backend.data.Product;
import com.vaadin.data.BeanValidationBinder;
import com.vaadin.data.Binder;
import com.vaadin.data.Result;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.data.ValueContext;
import com.vaadin.server.Page;
            format.setMaximumFractionDigits(0);
            format.setDecimalSeparatorAlwaysShown(false);
            format.setParseIntegerOnly(true);
            format.setGroupingUsed(false);
            return format;
        }

        @Override
        public Result<Integer> convertToModel(String value,
                ValueContext context) {
            Result<Integer> result = super.convertToModel(value, context);
            return result.map(stock -> stock == null ? 0 : stock);
        }

    }

    public ProductForm(SampleCrudLogic sampleCrudLogic) {
        super();
        addStyleName("product-form");
        viewLogic = sampleCrudLogic;

        // Mark the stock count field as numeric.
        // This affects the virtual keyboard shown on mobile devices.
        AttributeExtension stockFieldExtension = new AttributeExtension();
        stockFieldExtension.extend(stockCount);
        stockFieldExtension.setAttribute("type", "number");

        availability.setItems(Availability.values());
        availability.setEmptySelectionAllowed(false);

// Path: example-app/example-app-widgetset/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/AttributeExtension.java
// @JavaScript("attribute_extension_connector.js")
// public class AttributeExtension extends AbstractJavaScriptExtension {
// 
//     public void extend(TextField target) {
//         super.extend(target);
//     }
// 
//     @Override
//     protected AttributeExtensionState getState() {
//         return (AttributeExtensionState) super.getState();
//     }
// 
//     public void setAttribute(String attribute, String value) {
//         getState().attributes.put(attribute, value);
//     }
// }
// 
// Path: example-app/example-app-backend/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/backend/data/Availability.java
// public enum Availability {
//     COMING("Coming"), AVAILABLE("Available"), DISCONTINUED("Discontinued");
// 
//     private final String name;
// 
//     private Availability(String name) {
//         this.name = name;
//     }
// 
//     @Override
//     public String toString() {
//         return name;
//     }
// }
// 
// Path: example-app/example-app-backend/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/backend/data/Category.java
// public class Category implements Serializable {
// 
//     @NotNull
//     private int id;
//     @NotNull
//     private String name;
// 
//     public int getId() {
//         return id;
//     }
// 
//     public void setId(int id) {
//         this.id = id;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public void setName(String name) {
//         this.name = name;
//     }
// 
//     @Override
//     public String toString() {
//         return getName();
//     }
// }
// 
// Path: example-app/example-app-backend/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/backend/data/Product.java
// public class Product implements Serializable {
// 
//     @NotNull
//     private int id = -1;
//     @NotNull
//     @Size(min = 2, message = "Product name must have at least two characters")
//     private String productName = "";
//     @Min(0)
//     private BigDecimal price = BigDecimal.ZERO;
//     private Set<Category> category;
//     @Min(value = 0, message = "Can't have negative amount in stock")
//     private int stockCount = 0;
//     @NotNull
//     private Availability availability = Availability.COMING;
// 
//     public int getId() {
//         return id;
//     }
// 
//     public void setId(int id) {
//         this.id = id;
//     }
// 
//     public String getProductName() {
//         return productName;
//     }
// 
//     public void setProductName(String productName) {
//         this.productName = productName;
//     }
// 
//     public BigDecimal getPrice() {
//         return price;
//     }
// 
//     public void setPrice(BigDecimal price) {
//         this.price = price;
//     }
// 
//     public Set<Category> getCategory() {
//         return category;
//     }
// 
//     public void setCategory(Set<Category> category) {
//         this.category = category;
//     }
// 
//     public int getStockCount() {
//         return stockCount;
//     }
// 
//     public void setStockCount(int stockCount) {
//         this.stockCount = stockCount;
//     }
// 
//     public Availability getAvailability() {
//         return availability;
//     }
// 
//     public void setAvailability(Availability availability) {
//         this.availability = availability;
//     }
// 
// }


// Path: example-app/example-app-ui/src/main/java/com/github/mcollovati/vaadin/exampleapp/samples/crud/ProductForm.java
import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Locale;
import com.github.mcollovati.vaadin.exampleapp.samples.AttributeExtension;
import com.github.mcollovati.vaadin.exampleapp.samples.backend.data.Availability;
import com.github.mcollovati.vaadin.exampleapp.samples.backend.data.Category;
import com.github.mcollovati.vaadin.exampleapp.samples.backend.data.Product;
import com.vaadin.data.BeanValidationBinder;
import com.vaadin.data.Binder;
import com.vaadin.data.Result;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.data.ValueContext;
import com.vaadin.server.Page;

            format.setMaximumFractionDigits(0);
            format.setDecimalSeparatorAlwaysShown(false);
            format.setParseIntegerOnly(true);
            format.setGroupingUsed(false);
            return format;
        }

        @Override
        public Result<Integer> convertToModel(String value,
                ValueContext context) {
            Result<Integer> result = super.convertToModel(value, context);
            return result.map(stock -> stock == null ? 0 : stock);
        }

    }

    public ProductForm(SampleCrudLogic sampleCrudLogic) {
        super();
        addStyleName("product-form");
        viewLogic = sampleCrudLogic;

        // Mark the stock count field as numeric.
        // This affects the virtual keyboard shown on mobile devices.
        AttributeExtension stockFieldExtension = new AttributeExtension();
        stockFieldExtension.extend(stockCount);
        stockFieldExtension.setAttribute("type", "number");

        availability.setItems(Availability.values());
        availability.setEmptySelectionAllowed(false);

        binder = new BeanValidationBinder<>(Product.class);