DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Refcards
  3. Getting Started With Vaadin 10
refcard cover
Refcard #085

Getting Started With Vaadin 10

Modern Web Apps in Java

Vaadin makes it quick and simple to create HTML user interfaces using Java. Using a built-in selection of components, themes, data binding, and more, Vaadin is the ideal in web application development frameworks.

Free PDF for Easy Reference
refcard cover

Written By

author avatar Alejandro Duarte
Developer Advocate, MariaDB Corporation
author avatar Matti Tahvonen
Vaadin Expert, Vaadin
author avatar Marko Grönroos
Technical Writer, IT Mill
Table of Contents
► What Is Vaadin? ► Important Links ► “Hello, World” With Vaadin Flow ► Bootstrapping a Project ► Components ► Input Components ► HTML Components ► Notifications ► Sizing ► Margin and Padding ► Spacing ► Alignment ► Grow (Expanding Components) ► FormLayout ► Dialog ► Data Binding ► Routing and Navigation ► Custom Components ► Element API ► HTML Templates ► Themes ► Custom Styles
Section 1

What Is Vaadin?

Vaadin is an open-source web development platform for implementing HTML user interfaces (UI) using Java. Vaadin's strength is in its server-side API, Vaadin Flow, which allows not only the composition and implementation of UI components but also the direct manipulation of the Document Object Model (DOM) from the server.

With Vaadin Flow, developers implement the UI in Java running on the server side by using components such as text fields and buttons, arranging them into layouts, and connecting them to business logic through event listeners.

Vaadin Flow provides a variety of high-level ready-to-use UI components optimized for mobile and responsive design. It also includes data binding helpers, URL-based navigation, Web Components integration, and support for HTML templates.

Image title

Figure 1: Vaadin client-server architecture

Since modern IDEs can list classes, methods, and even Javadocs, this Refcard is a reference guide to things IDEs can’t quickly or directly tell you.

Section 2

Important Links

Website: https://vaadin.com

Vaadin Flow’s information page: https://vaadin.com/flow

Blog: https://vaadin.com/blog

Documentation: https://vaadin.com/docs

List of components: https://vaadin.com/components/browse

Components directory: https://vaadin.com/directory

Forum: https://vaadin.com/forum

GitHub: https://github.com/vaadin

Section 3

“Hello, World” With Vaadin Flow

The following example shows how to implement a simple UI with a text field and a button that, when clicked, invokes server-side logic that adds a greeting text to the layout:

@Route("hello-world")
public class HelloWorld extends VerticalLayout {

  public HelloWorld() {
    // two components:
    TextField name = new TextField("Name");
    Button greet = new Button("Greet");

    // add them to "this" layout (a VerticalLayout)
    add(name, greet);

    // add logic through event listeners
    greet.addClickListener(event ->
        add(new Span("Hello, " + name.getValue())));
  }

}


Image title

Figure 2: The “hello, world” application rendered as HTML in the browser

You implement user interfaces by extending an existing UI component such as VerticalLayout and annotating it with @Route. You can build up the UI by combining Vaadin components such as TextField, Button, Span, and many others to which you can add behavior by defining event listeners. The code runs on the server, which allows you to easily connect the UI to business logic. Optionally, you can customize the look and feel with CSS, bind UI components to backend data, manipulate the DOM from the server side in Java, and integrate Web Components.

Section 4

Bootstrapping a Project

The easiest way to bootstrap a new Vaadin Flow project is by using the project templates at vaadin.com/start. Select any of the templates for Vaadin version 10 or later, download and extract the zip file, and import it into your favorite IDE.

Alternatively, you can add the vaadin-core dependency in any Java web application and start using Vaadin Flow right away. With Maven, you can add the following to the pom.xml file:
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-core</artifactId>
    <version>LATEST</version>
</dependency>

Vaadin Flow requires the Servlet API version 3.1 or later. You can add it with Maven as follows:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
Section 5

Components

All Vaadin UI components directly or indirectly extend the Component class. You can add visual components and layouts into other layouts. There’s always one root component for each view that is mapped to a URL with a @Route annotation. Figure 3 shows the Component abstract class, interfaces it implements, and some of the relevant methods. All of the 3 interfaces are also functional interfaces.

Image title

Figure 3: The Component Interface

You’ll see this API pattern throughout the framework: abstract and concrete classes implementing mixin interfaces to build up the functionality of the component. For example, the CheckBox class directly or indirectly implements the HasSize, HasStyle, Focusable, ClickNotifier, and HasValueAndElement interfaces. You don’t need to memorize or even use this interface when creating a UI. However, knowing about them and their methods will help you to understand the features available in the UI components. The following table shows the mixin interfaces, their purposes, and their methods:

Interface Purpose Methods
BlurNotifier
Handle blur events
addBlurListener
ClickNotifier
Handle click events
addClickListener
CompositionNotifier
Handle DOM Composition events (text input)
addCompositionStartListener
addCompositionUpdateListener
addCompositionEndListener
Focusable
Focus, blur, and set tab order (extends HasElement, BlurNotifier, FocusNotifier, and HasEnabled)
setTabIndex
getTabIndex
focus
blur
FocusNotifier
Handle focus events
addFocusListener
HasAutocapitalize
Enables usage of the autocapitalize attribute
setAutocapitalize
getAutocapitalize
HasAutocomplete
Enables usage of the autocomplete attribute
setAutocomplete
getAutocomplete
HasAutocorrect
Enables usage of the autocorrect attribute
setAutocorrect
isAutocorrect
HasComponents
Add and remove child components (extends HasElements and HasEnabled)
add
remove
removeAll
HasDataProvider
Enable data providers
setDataProvider
setItems
HasElement
Retrieve underlying element
getElement
HasEnabled
Enable or disable components (extends HasElement)
setEnabled
isEnabled
HasOrderedComponents
Enable component order (extends HasComponents)
replace
indexOf
getComponentCount
getComponentAt
HasPrefixAndSuffix
Enable prefix and sufix slots for inserting components
setPrefixComponent
getPrefixComponent
setSufixComponent
getSufixComponent
HasSize
Enable component sizing
setWidth
getWidth
setHeight
getHeight
setSizeFull
setSizeUndefined
HasStyle
Enable CSS styles and CSS class names
addClassName
removeClassName
setClassName
getClassName
hasClassName
addClassNames
removeClassNames
getStyle
HasText
Enable content text
setText
getText
HasValidation
Enable input validation
setErrorMessage
getErrorMessage
setInvalid
isInvalid
HasValue
Enable user-editable values
setValue
getValue
addValueChangeListener
getEmptyValue
getOptionalValue
isEmpty
clear
setReadOnly
isReadOnly
setRequiredIndicatorVisible
isRequiredIndicatorVisible
HasValueAndElement
Extends HasValue, HasElement, and HasEnabled See extended interfaces
InputNotifier
Handle input events
addInputListener
KeyNotifier
Handle keyboard events
addKeyDownListener
addKeyPressListener
addKeyUpListener
PollNotifier
Handle events for asynchronous UI updates
addPollListener
SortNotifier
Handle sort evenrs
addSortListener
Section 6

Input Components

All input components implement HasSize (except ListBox), HasStyle, and, for most of them, HasValue and Focusable. The following table shows other of the mixing interfaces implemented by each input component:

Component Mixin interfaces
Button
ClickNotifier, HasText, Focusable
CheckBox
Focusable, ClickNotifier, HasValueAndElement
ComboBox
HasValidation, HasDataProvider, Focusable,  HasValueAndElement
DatePicker
HasValidation, Focusable,  HasValueAndElement
Grid
HasDataProvider, Focusable, SortNotifier
IronList
HasDataProvider, Focusable
ListBox
HasItemsAndComponents, HasDataProvider, HasValueAndElement
TextField
HasSize, HasValidation, HasPrefixAndSufix, InputNotifier, KeyNotifier, CompositionNotifier, HasStyle, Focusable,  HasValueAndElement
TextArea
HasSize, HasValidation,         HasPrefixAndSuffix, InputNotifier, KeyNotifier, CompositionNotifier,         HasAutocomplete, HasAutocapitalize, HasAutocorrect, HasStyle, Focusable, HasValueAndElement
PasswordField
HasSize, HasValidation,         HasPrefixAndSuffix,         InputNotifier, KeyNotifier, CompositionNotifier, HasAutocomplete,         HasAutocapitalize, HasAutocorrect, HasStyle, HasValueAndElement
RadioButtonGroup
HasItemsAndComponents, HasDataProvider, HasStyle, HasValueAndElement
Upload
HasSize, HasStyle
Section 7

HTML Components

There are UI components that represent most common elements in HTML and that extend the HtmlComponent class, for example: Div, Span, Section, Header, Footer, Article, H1, H2, H3, H4, H5, H6, Paragraph, Label, Anchor, OrderedList, ListItem, Image, and several others.

Tip: If you come from previous versions of Vaadin, note that the Label class is mapped to the label HTML element which is intended to be a label for an input element. Use components such as Span, Text, or Div, instead of Label when migrating from previous versions of Vaadin.

Section 8

Notifications

You can show notifications using the Notification class or its static show method. Notifications accept text or UI components:

new Notification(
    new VerticalLayout(
        new Span("Terms accepted."),
        new RouterLink("Learn More", TermsView.class)
    )
).open();
Section 9

Sizing

You can adjust the size of any Component that implement HasSize. The size of components can be set in fixed or relative units by either dimension (width or height) or be undefined to shrink to fit the content. You can either use explicit size or define it relatively from the area provided by the parent component. Notice that if all the components in a layout have relative size in a particular direction, the layout may not have undefined size in that direction!

Method Description
setWidth
setHeight
Set the component size in either fixed units (px, pt, pc, cm, mm, in, em, or rem) or as a relative percentage (%) of the available area provided by the containing layout. The null value or -1 means undefined size (see below), causing the component to shrink to fit the content.
setSizeFull
Sets both dimensions to 100% relative size.
setSizeUndefined
Sets both dimensions as undefined, causing the component to shrink to its minimum size.

Layouts

A UI is built hierarchically from layout components, or more generally component containers, with the actual interaction components as the leaf nodes of the components tree. Some layouts accept multiple components and others a limited number.

Image title

Figure 4: Vertical and horizontal layouts

Section 10

Margin and Padding

Certain layouts (those implementing ThemableLayout) support setting margin and padding programmatically. Setting setMargin(true) and setPadding(true) enables all paddings and margins respectively. The margin and padding sizes can be adjusted with a CSS rule. Example:

The Java class:

@HtmlImport("styles/shared-styles.html").

public class MyComponent extends VerticalLayout {
  public MyComponent() {
    addClassName("custom");
    ...
  }
}

And the corresponding styles file (src/main/webapp/frontend/styles/shared-styles.html):

<custom-style> 
  <style>
    .custom {
      margin-left: 10px;
      margin-right: 20px;
      margin-top: 30px;
      margin-bottom: 40px;
    }
  </style>
</custom-style>
Section 11

Spacing

Certain layout components also support the setSpacing(true) method that controls the space between the contained components. Spacing can be adjusted with CSS properties (for example, --lumo-space-m: 20px).

Section 12

Alignment

Alignment is based in the Flexbox layout mode of CSS. With Flexbox, you have two axis: main axis and cross axis. In a VerticalLayout, the main axis is a column that runs from top to bottom (flex-direction: column, in CSS). In a HorizontalLayout, the main layout is a row that runs from left to right (flex-direction: row, in CSS). You can override to column-reverse or row-reverse with CSS if needed. Since the axes have a direction, you specify the alignment in terms of start/end instead of left/right or top/bottom. To set the alignment in the main axis you can use the setJustifyContentMode method.

Image title

Figure 5: Main axis alignments

To set the alignment in the cross axis you can use the following methods:

Layout For all components For individual components
VerticalLayout
setAlignItems(Alignment)
setDefaultHorizontalAlignment(Alignment)
setAlignSelf(Alignment, HasElement)
setHorizontalComponentAlignment(Alignment, Component)
HorizontalLayout
setAlignItems(Alignment)
setDefaultVerticalAlignment(Alignment)
setAlignSelf(Alignment, HasElement)
setVerticalalComponentAlignment(Alignment, Component)
Section 13

Grow (Expanding Components)

The setFlexGrow method allows you to configure how to distribute the space in a layout for each component. The flex grow property specifies the amount of the available space inside the layout a component should take up, proportionally to the other components. For example, if all components have a flex grow value of 1, the remaining space in the layout will be distributed equally to all components inside the layout. If you set the flex grow value of one component to 2, that component will take twice the available space as the other components, and so on.

Image title

Figure 6: Flex grow example

Section 14

FormLayout

FormLayout is a responsive layout that helps making forms readable in all screen sizes. The following example sets a FormLayout that uses 3 columns for widths of 22em or more, 2 columns for widths between 21em and 22em, and 1 column for widths of less than 21em:

formLayout.setResponsiveSteps(
  new ResponsiveStep("0", 1),
  new ResponsiveStep("21em", 2),
  new ResponsiveStep("22em", 3));
Section 15

Dialog

Image title

Figure 7: The same form layout rendered in different screen sizes Dialog is a popup layout you can show in the UI using its open method. For example:

Dialog dialog = new Dialog(
        new Span("Press ESC to close"));
dialog.setCloseOnOutsideClick(false);
dialog.open();

Grid and Lazy Loading

Grid, the component that shows your data in a tabular format, often plays a central part in business applications. The easiest way to use the Grid component is to pass the data as a list, stream, or array. In the following code example, Person is the domain object (a Java Bean):

Grid grid = new Grid<>(Person.class);
grid.setItems(listOfPersons);
// define columns and the order as bean properties
// (default: show all)
grid.setColumns("name", "email");

Alternatively, you can define columns programmatically. In this case, you don’t need to pass the domain type as a constructor parameter:

Grid grid = new Grid<>();
grid.setItems(people);
grid.addColumn(Person::getName)
  .setCaption("Name");
...

The addColumn method returns a Column object that can be used to further configure the column and the data representation. In the above example, we only configure the caption of the column. With bean-based listing, you can get a reference to the Column with getColumn(“propertyName").

The setItems method stores the given data in your server memory for rapid access. If your data grid contains a lot of data and you wish to save server memory, you can also do a lazy binding with your backend using the setDataProvider method:

grid.setDataProvider(DataProvider.fromCallbacks(
  query -> service.findAll(query.getOffset(),
      query.getLimit()),
  query -> service.count()
));

The example above uses the easiest solution, in which you only pass two lambda expressions: the first to provide the given range of items, and the second to provides the total number of items available. Alternatively, you can provide a custom implementation of the DataProvider interface.

Section 16

Data Binding

Binder is a helper class that allows you to bind Java properties to UI components so that the input made by the end user automatically gets written to your domain model. The Binder class also helps you to convert values and validate the data. The following binds firstName (String) and age (Integer) to two text fields:

Binder<Person> b = new Binder<>();
b.forField(firstNameField)
    // additional configuration
    .asRequired("First name must be defined")
    .bind(Person::getFirstName, Person::setFirstName);
b.forField(ageField)
    .withNullRepresentation("")
    .withConverter(new StringToIntegerConverter(
            "Must be valid integer !"))
    .withValidator(integer -> integer > 0,
            "Age must be positive")
    .bind(p -> p.getAge(), (p, i) -> p.setAge(i));
b.setBean(person);

You can also use the bindInstanceFields method to bind all the Java member fields that are also Vaadin fields (those that extend HasValue):

public class Form extends VerticalLayout {
  private TextField name = new TextField("Name");
    @PropertyId(“phoneNumber") // optional
    private TextField phone = new TextField("Phone");

    Form form = new Form();
    ...
    binder.bindInstanceFields(form);
Section 17

Routing and Navigation

You can link UI components to URLs using the @Route annotation. Optionally, you can specify a layout (that must implement RouterLayout) where the annotated component should be rendered, and implement HasUrlParameter if the view accepts parameters:

@Route(layout=MainLayout.class)
public class GreetingView extends VerticalLayout
        implements HasUrlParameter<String> {
    @Override
    public void setParameter(BeforeEvent event,
                             String parameter) {
        add(new Span("Hello, " + parameter));
    }
}

To pass the value world as a parameter, you can request the application with a URL like http://yourdomain.com/greet/world. The route name is derived from the class name removing any trailing "View". If the class is named MainView or View, it will be mapped to a root URL (""). You can override this by using the value property of the @Route annotation.

The following interfaces allows you to interact with the navigation lifecycle. You can implement observers in a UI component or manually register listeners using the UI class.

Interface Description
BeforeLeaveObserver
BeforeLeaveListener

Allows delaying or canceling the navigation, or changing the navigation to a different destination
BeforeEnterObserver
BeforeEnterListener

Allows changing the navigation to a different destination
AfterNavigationObserver
AfterNavigationListener
Allows updating parts of the UI once the navigation has been completed
Section 18

Custom Components

You can create custom components by using existing components and extending Composite, which allows you to hide the API of the actual root level component:

public class CustomTextField extends Composite<Div> {
  private Label label;
  private Input input;

  public CustomTextField(String caption, String value) {
    label = new Label();
    label.setText(caption);
    input = new Input();
    input.setValue(value);

    getContent().add(label, input);
  }
}

Implementing custom input fields is done by extending the AbstractCompositeField, AbstractSinglePropertyField, or AbstractField depending on your requirements.

To implement component "containers," implement the HasComponents interface. It includes default implementations for add(Component…) and remove(Component…) that you can override if needed:

@Tag("div")
public class CustomContainer extends Component implements HasComponents {
  @Override
  public void add(Component... components) {
    for (Component c : components) {
      getElement().appendChild(c.getElement());
    }
  }
}
Section 19

Element API

The Element API of Vaadin Flow allows you to manipulate the DOM from server-side Java. Most often you should use the Element API to create custom components or do small modifications to existing ones. Since the Component class implements the HasElement interface, all UI components have an underlying Element object that you can get with component.getElement(). The Element class represents an HTML element in the DOM and contains methods to update and query various parts of an element, such as attributes and child elements.

The following example shows how to create an input field with a companion label and how to set properties and styles:

Element label = ElementFactory.createLabel("Name:");
label.setProperty("for", "name");

Element input = ElementFactory.createInput();
input.setProperty("id", "name");
input.setProperty("value", "Jane");
input.getStyle().set("font-size", "28px");
input.getStyle().set("margin-left", ".5em");
input.getStyle().set("background-color", "deepskyblue");
input.getStyle().set("color", "#fff");

Element div = ElementFactory.createDiv();
div.appendChild(label, input);

Notice that an Element is not a Component. You can however add Elements into Components as follows:

VerticalLayout layout = new VerticalLayout();
layout.getElement().appendChild(div);
Section 20

HTML Templates

You can define the UI, or parts of it using, HTML:

<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/vaadin-text-field/vaadin-text-field.html">
<link rel="import" href="../bower_components/vaadin-button/vaadin-button.html">
<dom-module id="example-template">
  <template>
    <vaadin-text-field label="Name:" value="{{name}}"></vaadin-text-field>
    <vaadin-button onclick="{{buttonClicked}}">Send</vaadin-button>
  </template>
  <script>
      class ExampleTemplate extends Polymer.Element {
          static get is() {
              return 'example-template'
          }
      }
      customElements.define(ExampleTemplate.is, ExampleTemplate);
  </script>
</dom-module>

Tip: You can visually edit HTML templates in Eclipse or IntelliJ with Vaadin Designer.

The previous template imports the Polymer library and two Web Components: vaadin-text-field and vaadin-button. These are static resources packaged as a WebJAR and included with Vaadin (from a Bower-based installation).

The name value and buttonClicked method can be used server-side as follows:

@Tag("example-template")
@HtmlImport("src/example-template.html")
public class ExampleTemplate extends PolymerTemplate<ExampleModel> {
  public interface ExampleModel extends TemplateModel {
    void setName(String value);
    String getName();
  }
  @EventHandler
  public void buttonClicked() {
    Notification.show("Hello, " + getModel().getName());
  }
}

The ExampleModel interface defines getters and setters for the HTML attributes defined in the template (for example {{name}} in the HTML file).

Section 21

Themes

Vaadin separates the appearance of the user interface from its logic using themes. Theming is done, as with any HTML content, by using CSS. Vaadin 10 includes the Lumo theme. It has a light (default) and a dark variant:

@Route(value = "")
@Theme(value = Lumo.class, variant = Lumo.DARK)
public class DarkApplication extends Div {
}

UI components have variants you can set with the Element API:

Button button = new Button("Save");
button.getElement().setAttribute("theme", "contrast primary”);
Section 22

Custom Styles

Since Vaadin components are based in Web Components, you have to put the CSS in an HTML file and load it with the @HtmlImport annotation:

@HtmlImport("frontend://styles/shared-styles.html")
public class MainLayout extends Div implements RouterLayout {
}

In the shared-styles.html file (located in src/main/webapp/frontend/styles) you can add any CSS rules as follows:

<custom-style>
  <style>
    ... CSS here ...
  </style>
</custom-style>

Lumo defines CSS custom properties that allow you to quickly modify the look and feel of an app:

<custom-style>
  <style>
    html {
      --lumo-font-family: Courier, monospace;
      --lumo-border-radius: 20px;
      --lumo-base-color: #fafbfc;
      --lumo-primary-color: #00b4f0;
    }
  </style>
</custom-style>

You can add CSS class names to any UI component using the addClassName and addClassNames methods:

addClassName("custom");

This class name can be used in a selector in the shared-styles-html file:

.custom {
  color: red;
}

Deployment

To deploy a Vaadin Flow application in a production environment, you must add the vaadin-maven-plugin in a Maven profile in the pom.xml file and compile the project specifying the name of the profile (for example, mvn clean package -PproductionMode). This performs three main tasks:

  • Transpilation: Converts ES6 JavaScript to ES5 JavaScript to support older browsers.

  • Minimization: Makes JavaScript files smaller.

  • Bundling: Bundling: Stitching together a group of modules into a single file.

For details about how to add the vaadin-maven-plugin, see https://vaadin.com/docs/v10/flow/production/tutorial-production-mode-basic.html.

In order to use the resources created by the vaadin-maven-plugin, you have to enable production mode using the @VaadinServletConfiguration annotation as follows:

@WebServlet(urlPatterns = "/*", asyncSupported = true,
initParams = { // optional
        @WebInitParam(name = "frontend.url.es6", value = "http://mydomain.com/es6/"),
        @WebInitParam(name = "frontend.url.es5", value = "http://mydomain.com/es5/") }
)
@VaadinServletConfiguration(productionMode = true)
public static class MainVaadinServlet extends VaadinServlet {}

You can also use system properties to override the @WebInitParam annotations. For example, you can pass the properties to the Jetty Maven Plugin as follows:

mvn jetty:run -Dvaadin.frontend.url.es6=http://mydomain.com/es6/ -Dvaadin.frontend.url.es5=http://mydomain.com/es5/

Notice that if you run the application using the Jetty Maven Plugin in production mode, you have to run it using mvn jetty:run-exploded.

Like This Refcard? Read More From DZone

related article thumbnail

DZone Article

related refcard thumbnail

Free DZone Refcard

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.linkDescription }}

{{ parent.urlSource.name }}
by
CORE
· {{ parent.articleDate | date:'MMM. dd, yyyy' }} {{ parent.linkDate | date:'MMM. dd, yyyy' }}
Tweet
{{ parent.views }} ViewsClicks
  • Edit
  • Delete
  • {{ parent.isLocked ? 'Enable' : 'Disable' }} comments
  • {{ parent.isLimited ? 'Remove comment limits' : 'Enable moderated comments' }}