Package swingtree

Class UIForTable<T extends JTable>

java.lang.Object
swingtree.UIForAnySwing<UIForTable<T>,T>
swingtree.UIForTable<T>

public final class UIForTable<T extends JTable> extends UIForAnySwing<UIForTable<T>,T>
A SwingTree builder node designed for configuring JTable instances allowing for a fluent API to build tables in a declarative way.
  • Method Details

    • _state

      protected swingtree.BuilderState<T> _state()
      Returns the state of the builder, which is a container for the wrapped component as well as it's type and current EventProcessor.
      Returns:
      The state of the builder.
    • _newBuilderWithState

      protected UIForTable<T> _newBuilderWithState(swingtree.BuilderState<T> newState)
      An internal wither method which creates a new builder instance with the provided BuilderState stored inside it.
      Parameters:
      newState - The new state which should be stored inside the new builder instance.
      Returns:
      A new builder instance with the provided state stored inside it.
    • withHeader

      public final UIForTable<T> withHeader(UIForTableHeader<?> header)
      Use this to set the table header.
      Parameters:
      header - The table header to be set.
      Returns:
      This builder node.
    • withHeader

      public final UIForTable<T> withHeader(JTableHeader header)
      Use this to set the table header.
      Parameters:
      header - The table header to be set.
      Returns:
      This builder node.
    • withRendererForColumn

      public final UIForTable<T> withRendererForColumn(String columnName, Configurator<RenderBuilder<T,Object>> renderBuilder)
      Use this to build a table cell renderer for a particular column. The second argument accepts a lambda function which exposes the builder API for a cell renderer. Here is an example of how to use this method:
      
           UI.table(myModel)
           .withRendererForColumn("column1", it -> it
               .when(String.class)
               .asText( cell -> "[" + cell.valueAsString().orElse("") + "]" ) )
           )
           .withRendererForColumn("column2", it -> it
               .when(Float.class)
               .asText( cell -> "(" + cell.valueAsString().orElse("") + "f)" ) )
               .when(Double.class)
               .asText( cell -> "(" + cell.valueAsString().orElse("") + "d)" ) )
           );
       
      The above example would render the first column of the table as a string surrounded by square brackets, and the second column as a float or double value surrounded by parentheses. Note that the API allows you to specify how specific types of table entry values should be rendered. This is done by calling the RenderBuilder.when(Class) method before calling the RenderAs.asText(Function) method.
      Parameters:
      columnName - The name of the column for which the cell renderer will be built.
      renderBuilder - A lambda function which exposes a fluent builder API for a cell renderer and returns the builder API for a cell renderer. Call the appropriate methods on the builder API to configure the cell renderer.
      Returns:
      This builder node.
    • withRendererForColumn

      public final UIForTable<T> withRendererForColumn(int columnIndex, Configurator<RenderBuilder<T,Object>> renderBuilder)
      Use this to build a table cell renderer for a particular column. The second argument accepts a lambda function which exposes the builder API for a cell renderer. Here an example of how this method may be used:
      
           UI.table(myModel)
           .withRendererForColumn(0, it -> it
               .when(String.class)
               .asText( cell -> "[" + cell.valueAsString().orElse("") + "]" ) )
           )
           .withRendererForColumn(1, it -> it
               .when(Float.class)
               .asText( cell -> "(" + cell.valueAsString().orElse("") + "f)" ) )
               .when(Double.class)
               .asText( cell -> "(" + cell.valueAsString().orElse("") + "d)" ) )
           );
       
      The above example would render the first column of the table as a string surrounded by square brackets, and the second column as a float or double value surrounded by parentheses. Note that the API allows you to specify how specific types of table entry values should be rendered. This is done by calling the RenderBuilder.when(Class) method before calling the RenderAs.asText(Function) method.
      Parameters:
      columnIndex - The index of the column for which the cell renderer will be built.
      renderBuilder - A lambda function which exposes a fluent builder API for a cell renderer and returns the builder API for a cell renderer. Call the appropriate methods on the builder API to configure the cell renderer.
      Returns:
      This builder node.
    • withCellRendererForColumn

      public final UIForTable<T> withCellRendererForColumn(String columnName, TableCellRenderer renderer)
      Use this to register a table cell renderer for a particular column. A TableCellRenderer is a supplier of Component instances which are used to render the cells of a table. Note that in SwingTree, the preferred way of defining a cell renderer for a particular column is through the withRendererForColumn(String, Configurator) method, which allows for a more fluent and declarative way of defining cell renderers.
      Parameters:
      columnName - The name of the column for which the cell renderer will be registered.
      renderer - The cell renderer to be registered.
      Returns:
      This builder node, to allow for builder-style method chaining.
    • withCellRendererForColumn

      public final UIForTable<T> withCellRendererForColumn(int columnIndex, TableCellRenderer renderer)
      Use this to register a table cell renderer for a particular column.
      A TableCellRenderer is a supplier of Component instances which are used to render the cells of a table. Note that in SwingTree, the preferred way of defining a cell renderer for a particular column is through the withRendererForColumn(int, Configurator) method, which allows for a more fluent and declarative way of defining cell renderers.
      Parameters:
      columnIndex - The index of the column for which the cell renderer will be registered.
      renderer - The cell renderer to be registered.
      Returns:
      This builder node.
    • withCellRenderer

      public final UIForTable<T> withCellRenderer(TableCellRenderer renderer)
      Use this to register a table cell renderer for all columns of this table.
      A TableCellRenderer is a supplier of Component instances which are used to render the cells of a table.

      Note that in SwingTree, the preferred way of defining a cell renderer is through the withRenderer(Configurator) method, which allows for a more fluent and declarative way of defining cell renderers.
      Parameters:
      renderer - A provider of Component instances which are used to render the cells of a table.
      Returns:
      This builder instance, to allow for method chaining.
    • withRenderer

      public final UIForTable<T> withRenderer(Configurator<RenderBuilder<T,Object>> renderBuilder)
      Use this to define a table cell renderer for all columns of this table using the fluent builder API exposed to the provided lambda function.
      Here is an example of how this method is used:
      
          UI.table()
          .withRenderer( it -> it
              .when(SomeDataType.class)
              .asText( cell -> cell.value().get().toString() )
          )
          // ...
        
      You may want to know that a similar API is also available for the JList and JComboBox components, see UIForList.withRenderer(Configurator), UIForCombo.withRenderer(Configurator) for more information.
      Parameters:
      renderBuilder - A lambda function which exposes the builder API for a cell renderer and returns the builder API for a cell renderer. Call the appropriate methods on the builder API to configure the cell renderer.
      Returns:
      This builder node.
    • withCellEditorForColumn

      public final UIForTable<T> withCellEditorForColumn(String columnName, TableCellEditor editor)
      Use this to register a table cell editor for a particular column.
      Parameters:
      columnName - The name of the column for which the cell editor will be registered.
      editor - The cell editor to be registered.
      Returns:
      This builder instance, to allow for method chaining.
    • withCellEditorForColumn

      public final UIForTable<T> withCellEditorForColumn(int columnIndex, TableCellEditor editor)
      Use this to register a table cell editor for a particular column.
      Parameters:
      columnIndex - The index of the column for which the cell editor will be registered.
      editor - The cell editor to be registered.
      Returns:
      This builder node, to allow for builder-style method chaining.
    • withModel

      public final UIForTable<T> withModel(Buildable<BasicTableModel> dataModelBuilder)
      Use this to set a table model. The provided argument is a builder object whose build method will be called for you instead of having to call the build method on the builder object yourself.
      Parameters:
      dataModelBuilder - The builder object which will be used to build and then set the table model.
      Returns:
      This builder object.
    • withModel

      public final UIForTable<T> withModel(Configurator<BasicTableModel.Builder<Object>> dataModelBuilder)
      Exposes a fluent builder API for a table model.
      Here an example demonstrating how this API is typically used as part of a UI declaration:
      
        UI.table().withModel( m -> m
            .colName( col -> new String[]{"X", "Y", "Z"}[col] )
            .colCount( () -> 3 )
            .rowCount( () -> data.size() )
            .getsEntryAt( (r, c) -> data[r][c] )
            .updateOn(update)
        )
        
      The builder API is exposed to the lambda function passed to this method. The actually TableModel is built internally and then set on the table.
      Parameters:
      dataModelBuilder - A lambda function which receives a builder API for a table model
      Returns:
      This builder instance, to allow for further method chaining.
    • withModel

      public final <E> UIForTable<T> withModel(Class<E> itemType, Configurator<BasicTableModel.Builder<E>> dataModelBuilder)
      Exposes a fluent builder API for a table model holding a specific type of entry.
      Here an example demonstrating how this API is typically used as part of a UI declaration:
      
        UI.table().withModel(Double.class, m -> m
            .colName( col -> new String[]{"X", "Y", "Z"}[col] )
            .colCount( () -> 3 )
            .rowCount( () -> data.size() )
            .getsEntryAt( (r, c) -> data[r][c] )
            .updateOn(update)
        )
        
      In this example, the table model is built for a Double based data source. So here the data array is a two-dimensional array of Doubles.

      Note that the builder API is exposed to the lambda function passed to this method. The actual TableModel is built internally and then installed on the table component.

      You can also use the UIFactoryMethods.table(Configurator) factory method to directly create a table with a custom table model.

      Parameters:
      itemType - The type of the table entry Objects.
      dataModelBuilder - A lambda function which receives a builder API for a table model
      Returns:
      This builder instance, to allow for further method chaining.
    • withModel

      public final UIForTable<T> withModel(BasicTableModel model)
      Use this to set a basic table model for this table.
      Parameters:
      model - The model for the table model.
      Returns:
      This builder object.
    • withModel

      public final <E> UIForTable<T> withModel(UI.ListData mode, TableListDataSource<E> dataSource)
      Use this instead of JTable.setModel(TableModel) if your table data can be represented by either a row major List of Lists of entry Objects (a list of rows)
      or a columns major List of Lists of entry Objects (a list of columns).
      This method will automatically create a AbstractTableModel instance for you.

      Please note that when the data of the provided data source changes (i.e. when the data source is a List and the list is modified), the table model will not be updated automatically! Use updateTableOn(sprouts.Event) to bind an update Event to the table model.

      Type Parameters:
      E - The type of the table entry Objects.
      Parameters:
      mode - An enum which configures the layout as well as modifiability of the table in a readable fashion.
      dataSource - The TableListDataSource returning a list matrix which will be used to populate the table.
      Returns:
      This builder node.
    • withModel

      public final <E> UIForTable<T> withModel(UI.MapData mode, TableMapDataSource<E> dataSource)
      Use this instead of JTable.setModel(TableModel) if your table data can be represented based on a map of column names to lists of table entries (basically a column major matrix).
      This method will automatically create a AbstractTableModel instance for you.

      Please note that when the data of the provided data source changes (i.e. when the data source is a Map which gets modified), the table model will not be updated automatically! Use updateTableOn(sprouts.Event) to bind an update Event to the table model.

      Type Parameters:
      E - The type of the table entry Objects.
      Parameters:
      mode - An enum which configures the modifiability of the table in a readable fashion.
      dataSource - The TableMapDataSource returning a column major map based matrix which will be used to populate the table.
      Returns:
      This builder node.
    • updateTableOn

      public final UIForTable<T> updateTableOn(sprouts.Event event)
      Use this to bind an Event to the TableModel of this table which will trigger the AbstractTableModel.fireTableDataChanged() method. This is useful if you want to update the table when the data source changes.
      Parameters:
      event - The event to be bound.
      Returns:
      This builder node, for chaining.
    • getType

      public final Class<T> getType()
      The type class of the component managed by this builder. See documentation for method "build" for more information.
      Returns:
      The type class of the component managed by this builder.
    • getComponent

      @Deprecated public final T getComponent()
      Deprecated.
      Use get(Class) instead.
      The component managed by this builder.
      Returns:
      The component managed by this builder.
      Throws:
      IllegalStateException - if this method is called from a thread other than the EDT and this UI is configured to be decoupled from the application thread. See UIFactoryMethods.use(EventProcessor, Supplier).
    • component

      @Deprecated public final OptionalUI<T> component()
      Deprecated.
      Use get(Class) instead.
      The optional component managed by this builder.
      Returns:
      An OptionalUI wrapping a component or null. This optional will throw an exception if the application has an application thread (see UIFactoryMethods.use(EventProcessor, Supplier)) and this method is called from a thread other than the EDT.
    • peek

      public final UIForTable<T> peek(Peeker<T> action)
      Use this if you wish to access the component wrapped by this builder directly. This is useful for more fine-grained control, like for example calling methods like "setName", "setTitle", and so on...
      This method accepts a lambda to which the component wrapped by this builder will be supplied. The lambda can then call said methods or perform other tasks which might be relevant to the component while also not breaking the benefits of nesting and method chaining provided by this class...
      The below example shows how this method allows for more fine-grained control over the wrapped component:
      
            UI.panel()
            peek( panel -> panel.setDebugGraphicsOptions(true) );
        


      Parameters:
      action - A Consumer lambda which simply returned the wrapped JComponent type for interacting it.
      Returns:
      This very instance, which enables builder-style method chaining.
    • applyIf

      public final UIForTable<T> applyIf(boolean condition, Consumer<UIForTable<T>> building)
      Use this to only build a certain part of the UI if the provided boolean condition is true. Which is to say, if the condition is false, then the second lambda is ignored, if on the other hand the condition is true, then the second lambda is executed with the current builder instance passed to it as a parameter. Inside the lambda, one can then continue building the UI while also not breaking the benefits of nesting and method chaining provided by this builder...

      This is in essence a more advanced version of apply(Consumer).
      Here a simple usage example:

      
          UI.panel()
          .applyIf( userIsLoggedIn, ui -> ui
            .add( UI.label("Welcome back!") )
            .add( UI.button("Logout")).onClick( () -> logout() )
            .add( UI.button("Settings")).onClick( () -> showSettings() )
          )
          .applyIf( !userIsLoggedIn, ui -> ui
            .add( UI.label("Please login to continue.") )
            .add( UI.button("Login")).onClick( () -> login() );
          );
        
      Here we use theis method to build a panel with different content depending on whether the user is logged in or not.

      Parameters:
      condition - The truth value which determines if the second consumer lambda is executed or not.
      building - A Consumer lambda which simply consumes this builder instance.
      Returns:
      This very instance, which enables builder-style method chaining.
    • applyIfPresent

      public final UIForTable<T> applyIfPresent(Optional<Consumer<UIForTable<T>>> building)
      Allows you to build declarative UI conditionally, meaning that the UI is only built if the provided Optional value is present. If the value is not present, meaning it is null, then the second lambda (containing UI declarations relevant to the value) is simply ignored.

      Consider the following example:

      
       // In your view model:
       public Optional<MySubModel> getM() {
         return Optional.ofNullable(this.model);
       }
      
       // In your view:
       UI.panel()
       .add(UI.label("Maybe Sub Model:"))
       .applyIfPresent(vm.getM().map(m->ui->ui
         .add(UI.label("Hello Sub Model!"))
         .add(UI.label("A:")
         .add(UI.textField(m.getA()))
         .add(UI.label("B:"))
         .add(UI.textField(m.getB()))
         // ...
       ))
       .add(UI.label("Some other stuff..."));
       
      The applyIfPresent method takes an Optional<Consumer<I>> as parameter, where I is the type of the UI builder. This allows you to map the optional value to a consumer which is only executed if the value is present. If the optional value is present, the consumer is executed with the current UI builder as a parameter, which allows you to continue building the UI as usual.
      The m->ui->ui may look a bit confusing at first, but it is simply a lambda expression which takes the optional value and returns a consumer (ui->ui... ) which takes the UI builder as a parameter.
      This is in essence a more advanced Optional centric version of applyIf(boolean, Consumer) and apply(Consumer).
      Parameters:
      building - An optional consumer lambda which simply consumes this builder node.
      Returns:
      This very instance, which enables builder-style method chaining.
    • apply

      public final UIForTable<T> apply(Consumer<UIForTable<T>> building)
      Use this to continue building UI inside a provided lambda if you need to introduce some imperative code in between the building process.
      This is especially useful for when you need to build UI based on loops. The current builder instance will simply be supplied to the provided Consumer lambda. Inside the supplied lambda, you can then continue building the UI while also not breaking the benefits of nesting and method chaining, effectively preserving the declarative nature of the builder.

      Here is a simple example of how this method can be used to build a panel with a variable amount of images displayed in a grid:
      
            UI.panel("wrap 3")
            .apply( ui -> {
                for ( String path : imagePaths )
                    ui.add( UI.label(UI.icon(path)) );
            });
        


      Here is another example of how this method can be used to build a panel with a variable amount of buttons displayed in a grid:
      
          UI.panel("wrap 4")
          .apply( ui -> {
            for ( int i = 0; i < numOfButtons; i++ )
                ui.add( UI.button("Button " + i)
                .onClick( () -> {...} );
          });
        


      Parameters:
      building - A Consumer lambda which simply consumes this builder instance.
      Returns:
      This very instance, which enables builder-style method chaining.
    • get

      public final T get(Class<T> type)
      This method completes the building process for the wrapped JComponent type by returning it. However, it also expects the user to pass the class of the JComponent wrapped by this builder! This is not out of necessity but for better readability when using the builder in more extensive ways where the beginning and end of the method chaining and nesting of the builder does not fit on one screen.
      In such cases the expression ".get(MyJComponent.class)" helps to identify which type of JComponent is currently being built on a given nesting layer...

      Here is a simple example that demonstrates this technique using a JPanel and a JMenuBar:
      
            UI.panel()
            .add(
                UI.menuBar()
                .add( UI.menu("File") )
                .add( UI.menuItem("Open") )
                .add( UI.menuItem("Save") )
                // ...
                .add( UI.menuItem("Exit") )
                .get(JMenuBar.class)
            )
            .add( UI.button("Click me!") )
            .get(JPanel.class);
        
      As you can see, the expression ".get(JMenuBar.class)" as well as the expression ".get(JPanel.class)" at the end of the builder chain help to identify which type of JComponent is currently being built and returned.
      Parameters:
      type - The type class of the component which this builder wraps.
      Returns:
      The result of the building process, namely: a type of JComponent.
    • add

      @SafeVarargs public final UIForTable<T> add(JComponent... components)
      This builder class expects its implementations to be builder types for anything which can be built in a nested tree-like structure. Implementations of this abstract method ought to enable support for nested building.

      Parameters:
      components - An array of component instances which ought to be added to the wrapped component type.
      Returns:
      This very instance, which enables builder-style method chaining.
    • add

      public final <T extends JComponent> UIForTable<T> add(UIForAnySwing<?,T> builder)
      Uses the supplied builder to build its component and then add it to the component that is being built by this builder instance. This directly allows you to nest your builder based UI declarations in an HTML-like fashion.
      Type Parameters:
      T - The type of the JComponent which is wrapped by the provided builder.
      Parameters:
      builder - A builder for another JComponent instance which ought to be added to the wrapped component type.
      Returns:
      This very instance, which enables builder-style method chaining.
    • add

      @SafeVarargs public final <B extends swingtree.UIForAnything<?, ?, JComponent>> UIForTable<T> add(B... builders)
      This method provides the same functionality as the other "add" methods. However, it bypasses the necessity to call the "get" method by calling it internally for you.
      This helps to improve readability, especially when the degree of nesting is very low.
      Type Parameters:
      B - The type of the builder instances which are used to configure the components that will be added to the component wrapped by this builder.
      Parameters:
      builders - An array of builder instances whose JComponents ought to be added to the one wrapped by this builder.
      Returns:
      This very instance, which enables builder-style method chaining.
    • add

      public final UIForTable<T> add(List<JComponent> components)
      This builder class expects its implementations to be builder types for anything which can be built in a nested tree-like structure. Implementations of this abstract method ought to enable support for nested building.

      Parameters:
      components - A list of component instances which ought to be added to the wrapped component type.
      Returns:
      This very instance, which enables builder-style method chaining.
    • _addBuildersTo

      @SafeVarargs protected final <B extends swingtree.UIForAnything<?, ?, JComponent>> void _addBuildersTo(T thisComponent, B... builders)
    • _addComponentsTo

      @SafeVarargs protected final void _addComponentsTo(T thisComponent, JComponent... componentsToBeAdded)
    • _addBuilderTo

      protected final void _addBuilderTo(T thisComponent, swingtree.UIForAnything<?,?,?> builder, @Nullable Object conf)
    • _with

      protected final swingtree.UIForAnything<UIForTable<T>,T,JComponent> _with(Consumer<T> componentMutator)
      Creates a new builder with the provided component mutation applied to the wrapped component.
      Note that the SwingTree builders are immutable, which means that this method does not mutate the current builder instance, but instead creates a new builder instance with a new BuilderState which contains the provided component mutation (see BuilderState.withMutator(Consumer)). Also see _newBuilderWithState(BuilderState).
      Parameters:
      componentMutator - A consumer lambda which receives the wrapped component and is then used to apply some builder action to it.
      Returns:
      A new builder instance with the provided component mutation applied to the wrapped component.
    • _runInUI

      protected final void _runInUI(Runnable action)
      A convenient shortcut to the EventProcessor.registerUIEvent(Runnable) method to the current EventProcessor attached to the current BuilderState. In practice, this method will ultimately just delegate tasks to the AWT Event Dispatch Thread (EDT).
      Parameters:
      action - An action which should be executed by the UI thread, which is determined by implementations of the EventProcessor, also see UIFactoryMethods.use(EventProcessor, Supplier).
      Usually the UI thread is AWT's Event Dispatch Thread (EDT).
    • _runInApp

      protected final void _runInApp(Runnable action)
      A convenient delegate to the EventProcessor.registerAppEvent(Runnable) method, which allows you to execute an action on the current application thread. To configure the current EventProcessor see UIFactoryMethods.use(EventProcessor, Supplier) or the underlying SwingTree.setEventProcessor(EventProcessor) method.
      Parameters:
      action - An action which should be executed by the application thread, which is determined by implementations of the current EventProcessor, also see UIFactoryMethods.use(EventProcessor, Supplier).
    • _runInApp

      protected final <T> void _runInApp(T value, Consumer<T> action)
      A convenient delegate to the EventProcessor.registerAppEvent(Runnable) method, which allows you to execute an action on the current application thread. Which thread executes these tasks is determined by the current EventProcessor. Usually this is the EventProcessor.COUPLED or EventProcessor.COUPLED_STRICT event processor.
      Type Parameters:
      T - The type of the value.
      Parameters:
      value - A value which should be captured and then passed to the provided action on the current application thread (see EventProcessor and UIFactoryMethods.use(EventProcessor, Supplier)).
      action - A consumer lambda which is executed by the application thread and receives the provided value.
    • _onShow

      protected final <T> void _onShow(sprouts.Val<T> val, T thisComponent, BiConsumer<T,T> displayAction)
      Use this to register a state change listener for the provided property which will be executed by the UI thread (see EventProcessor).
      Type Parameters:
      T - The type of the item wrapped by the provided property.
      Parameters:
      val - A property whose state changes should be listened to on the UI thread.
      thisComponent - The component which is wrapped by this builder.
      displayAction - A consumer lambda receiving the provided value and is then executed by the UI thread.
    • _withOnShow

      protected final <T> swingtree.UIForAnything<UIForTable<T>,T,JComponent> _withOnShow(sprouts.Val<T> val, BiConsumer<T,T> displayAction)
    • _onShow

      protected final <T> void _onShow(sprouts.Vals<T> vals, T c, BiConsumer<T,sprouts.ValsDelegate<T>> displayAction)
      Use this to register a state change listener for the provided property list which will be executed by the UI thread (see EventProcessor).
      Type Parameters:
      T - The type of the items wrapped by the provided property list.
      Parameters:
      vals - A property list whose state changes should be listened to on the UI thread.
      c - The component which is wrapped by this builder.
      displayAction - A consumer lambda receiving the action delegate and is then executed by the UI thread.
    • _withOnShow

      protected final <T> swingtree.UIForAnything<UIForTable<T>,T,JComponent> _withOnShow(sprouts.Vals<T> vals, BiConsumer<T,sprouts.ValsDelegate<T>> displayAction)
    • _this

      protected final UIForTable<T> _this()
      Exposes the this-pointer of the builder instance cast to the I type parameter of the builder class.
      This is done to reduce the amount of type casting and warnings in the codebase.
      Returns:
      The builder instance itself based on the type parameter <I>.
    • _disposeState

      protected final void _disposeState()
      This method is used to dispose of the state of the builder, which means that the builder state disposes of its reference to either the wrapped component or the wrapped component or the composite of component factories which are used to build the wrapped component eagerly each time the wrapped component is accessed.
      This is important to avoid memory leaks, as a component is typically part of a tree of components, and if one component is not garbage collected, then the whole tree is not garbage collected.
    • hashCode

      public final int hashCode()
      Overrides:
      hashCode in class Object
    • equals

      public final boolean equals(Object obj)
      Overrides:
      equals in class Object
    • toString

      public final String toString()
      Overrides:
      toString in class Object