From 13b99cfa265913ab8cb2d948f2ab2bf152a959e4 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 26 Aug 2016 11:36:24 +0300 Subject: Move remaining Vaadin 7 classes to the compatibility package Change-Id: I3be37350a638028d89fb527a3dfb09e74fdebeed --- .../src/main/java/com/vaadin/v7/data/Buffered.java | 197 ++++++ .../com/vaadin/v7/data/BufferedValidatable.java | 45 ++ .../src/main/java/com/vaadin/v7/data/Property.java | 425 +++++++++++ .../main/java/com/vaadin/v7/data/Validatable.java | 130 ++++ .../main/java/com/vaadin/v7/data/Validator.java | 198 ++++++ .../com/vaadin/v7/data/util/AbstractProperty.java | 270 +++++++ .../main/java/com/vaadin/v7/data/util/ListSet.java | 276 ++++++++ .../com/vaadin/v7/data/util/MethodProperty.java | 774 +++++++++++++++++++++ .../v7/data/util/MethodPropertyDescriptor.java | 148 ++++ .../vaadin/v7/data/util/NestedMethodProperty.java | 269 +++++++ .../v7/data/util/NestedPropertyDescriptor.java | 72 ++ .../com/vaadin/v7/data/util/ObjectProperty.java | 142 ++++ .../com/vaadin/v7/data/util/PropertyFormatter.java | 257 +++++++ .../com/vaadin/v7/data/util/TextFileProperty.java | 157 +++++ .../v7/data/util/TransactionalPropertyWrapper.java | 153 ++++ .../v7/data/util/VaadinPropertyDescriptor.java | 55 ++ .../server/AbstractPropertyListenersTest.java | 30 + .../vaadin/tests/server/PropertyFormatterTest.java | 75 ++ .../src/main/java/com/vaadin/v7/data/Buffered.java | 197 ------ .../com/vaadin/v7/data/BufferedValidatable.java | 45 -- .../src/main/java/com/vaadin/v7/data/Property.java | 425 ----------- .../main/java/com/vaadin/v7/data/Validatable.java | 130 ---- .../main/java/com/vaadin/v7/data/Validator.java | 198 ------ .../com/vaadin/v7/data/util/AbstractProperty.java | 270 ------- .../main/java/com/vaadin/v7/data/util/ListSet.java | 276 -------- .../com/vaadin/v7/data/util/MethodProperty.java | 774 --------------------- .../v7/data/util/MethodPropertyDescriptor.java | 148 ---- .../vaadin/v7/data/util/NestedMethodProperty.java | 269 ------- .../v7/data/util/NestedPropertyDescriptor.java | 72 -- .../com/vaadin/v7/data/util/ObjectProperty.java | 142 ---- .../com/vaadin/v7/data/util/PropertyFormatter.java | 257 ------- .../com/vaadin/v7/data/util/TextFileProperty.java | 157 ----- .../v7/data/util/TransactionalPropertyWrapper.java | 153 ---- .../v7/data/util/VaadinPropertyDescriptor.java | 55 -- .../server/AbstractPropertyListenersTest.java | 30 - .../vaadin/tests/server/PropertyFormatterTest.java | 75 -- .../server/component/button/ButtonClickTest.java | 9 +- 37 files changed, 3678 insertions(+), 3677 deletions(-) create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/Property.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/Validatable.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/ListSet.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java create mode 100644 compatibility-server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java create mode 100644 compatibility-server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java create mode 100644 compatibility-server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/Buffered.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/Property.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/Validatable.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/Validator.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/ListSet.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java delete mode 100644 server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java delete mode 100644 server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java delete mode 100644 server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java new file mode 100644 index 0000000000..025a43fbba --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java @@ -0,0 +1,197 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data; + +import java.io.Serializable; + +import com.vaadin.server.AbstractErrorMessage; +import com.vaadin.server.ErrorMessage; +import com.vaadin.server.ErrorMessage.ErrorLevel; +import com.vaadin.server.ErrorMessageProducer; +import com.vaadin.server.UserError; +import com.vaadin.v7.data.Validator.InvalidValueException; + +/** + *

+ * Defines the interface to commit and discard changes to an object, supporting + * buffering. + * + *

+ * In buffered mode the initial value is read from the data source and + * then buffered. Any subsequential writes or reads will be done on the buffered + * value. Calling {@link #commit()} will write the buffered value to the data + * source while calling {@link #discard()} while discard the buffered value and + * re-read the value from the data source. + * + *

+ * In non-buffered mode the value is always read directly from the data + * source. Any write is done directly to the data source with no buffering in + * between. Reads are also done directly from the data source. Calling + * {@link #commit()} or {@link #discard()} in this mode is efficiently a no-op. + * + * @author Vaadin Ltd. + * @since 3.0 + */ +public interface Buffered extends Serializable { + + /** + * Updates all changes since the previous commit to the data source. The + * value stored in the object will always be updated into the data source + * when commit is called. + * + * @throws SourceException + * if the operation fails because of an exception is thrown by + * the data source. The cause is included in the exception. + * @throws InvalidValueException + * if the operation fails because validation is enabled and the + * values do not validate + */ + public void commit() throws SourceException, InvalidValueException; + + /** + * Discards all changes since last commit. The object updates its value from + * the data source. + * + * @throws SourceException + * if the operation fails because of an exception is thrown by + * the data source. The cause is included in the exception. + */ + public void discard() throws SourceException; + + /** + * Sets the buffered mode to the specified status. + *

+ * When in buffered mode, an internal buffer will be used to store changes + * until {@link #commit()} is called. Calling {@link #discard()} will revert + * the internal buffer to the value of the data source. + *

+ * When in non-buffered mode both read and write operations will be done + * directly on the data source. In this mode the {@link #commit()} and + * {@link #discard()} methods serve no purpose. + * + * @param buffered + * true if buffered mode should be turned on, false otherwise + * @since 7.0 + */ + public void setBuffered(boolean buffered); + + /** + * Checks the buffered mode + * + * @return true if buffered mode is on, false otherwise + * @since 7.0 + */ + public boolean isBuffered(); + + /** + * Tests if the value stored in the object has been modified since it was + * last updated from the data source. + * + * @return true if the value in the object has been modified + * since the last data source update, false if not. + */ + public boolean isModified(); + + /** + * An exception that signals that one or more exceptions occurred while a + * buffered object tried to access its data source or if there is a problem + * in processing a data source. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + @SuppressWarnings("serial") + public class SourceException extends RuntimeException + implements Serializable, ErrorMessageProducer { + + /** Source class implementing the buffered interface */ + private final Buffered source; + + /** Original cause of the source exception */ + private Throwable[] causes = {}; + + /** + * Creates a source exception that does not include a cause. + * + * @param source + * the source object implementing the Buffered interface. + */ + public SourceException(Buffered source) { + this.source = source; + } + + /** + * Creates a source exception from multiple causes. + * + * @param source + * the source object implementing the Buffered interface. + * @param causes + * the original causes for this exception. + */ + public SourceException(Buffered source, Throwable... causes) { + this.source = source; + this.causes = causes; + } + + /** + * Gets the cause of the exception. + * + * @return The (first) cause for the exception, null if no cause. + */ + @Override + public final Throwable getCause() { + if (causes.length == 0) { + return null; + } + return causes[0]; + } + + /** + * Gets all the causes for this exception. + * + * @return throwables that caused this exception + */ + public final Throwable[] getCauses() { + return causes; + } + + /** + * Gets a source of the exception. + * + * @return the Buffered object which generated this exception. + */ + public Buffered getSource() { + return source; + } + + @Override + public ErrorMessage getErrorMessage() { + // no message, only the causes to be painted + UserError error = new UserError(null); + // in practice, this was always ERROR in Vaadin 6 unless tweaked in + // custom exceptions implementing ErrorMessage + error.setErrorLevel(ErrorLevel.ERROR); + // causes + for (Throwable nestedException : getCauses()) { + error.addCause(AbstractErrorMessage + .getErrorMessageForException(nestedException)); + } + return error; + } + + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java b/compatibility-server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java new file mode 100644 index 0000000000..ea0b3c0ebd --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data; + +import java.io.Serializable; + +/** + *

+ * This interface defines the combination of Validatable and + * Buffered interfaces. The combination of the interfaces defines + * if the invalid data is committed to datasource. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ +public interface BufferedValidatable + extends Buffered, Validatable, Serializable { + + /** + * Tests if the invalid data is committed to datasource. The default is + * false. + */ + public boolean isInvalidCommitted(); + + /** + * Sets if the invalid data should be committed to datasource. The default + * is false. + */ + public void setInvalidCommitted(boolean isCommitted); +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Property.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Property.java new file mode 100644 index 0000000000..21129a64f9 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Property.java @@ -0,0 +1,425 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data; + +import java.io.Serializable; + +/** + *

+ * The Property is a simple data object that contains one typed + * value. This interface contains methods to inspect and modify the stored value + * and its type, and the object's read-only state. + *

+ * + *

+ * The Property also defines the events + * ReadOnlyStatusChangeEvent and ValueChangeEvent, and + * the associated listener and notifier interfaces. + *

+ * + *

+ * The Property.Viewer interface should be used to attach the + * Property to an external data source. This way the value in the data source + * can be inspected using the Property interface. + *

+ * + *

+ * The Property.editor interface should be implemented if the value + * needs to be changed through the implementing class. + *

+ * + * @param T + * type of values of the property + * + * @author Vaadin Ltd + * @since 3.0 + */ +public interface Property extends Serializable { + + /** + * Gets the value stored in the Property. The returned object is compatible + * with the class returned by getType(). + * + * @return the value stored in the Property + */ + public T getValue(); + + /** + * Sets the value of the Property. + *

+ * Implementing this functionality is optional. If the functionality is + * missing, one should declare the Property to be in read-only mode and + * throw Property.ReadOnlyException in this function. + *

+ * + * Note : Since Vaadin 7.0, setting the value of a non-String property as a + * String is no longer supported. + * + * @param newValue + * New value of the Property. This should be assignable to the + * type returned by getType + * + * @throws Property.ReadOnlyException + * if the object is in read-only mode + */ + public void setValue(T newValue) throws Property.ReadOnlyException; + + /** + * Returns the type of the Property. The methods getValue and + * setValue must be compatible with this type: one must be able + * to safely cast the value returned from getValue to the given + * type and pass any variable assignable to this type as an argument to + * setValue. + * + * @return type of the Property + */ + public Class getType(); + + /** + * Tests if the Property is in read-only mode. In read-only mode calls to + * the method setValue will throw + * ReadOnlyException and will not modify the value of the + * Property. + * + * @return true if the Property is in read-only mode, + * false if it's not + */ + public boolean isReadOnly(); + + /** + * Sets the Property's read-only mode to the specified status. + * + * This functionality is optional, but all properties must implement the + * isReadOnly mode query correctly. + * + * @param newStatus + * new read-only status of the Property + */ + public void setReadOnly(boolean newStatus); + + /** + * A Property that is capable of handle a transaction that can end in commit + * or rollback. + * + * Note that this does not refer to e.g. database transactions but rather + * two-phase commit that allows resetting old field values (in e.g. a + * FieldGroup) if the commit of one of the properties fails after other + * properties have already been committed. + * + * @param + * The type of the property + * @author Vaadin Ltd + * @since 7.0 + */ + public interface Transactional extends Property { + + /** + * Starts a transaction. + * + *

+ * If the value is set during a transaction the value must not replace + * the original value until {@link #commit()} is called. Still, + * {@link #getValue()} must return the current value set in the + * transaction. Calling {@link #rollback()} while in a transaction must + * rollback the value to what it was before the transaction started. + *

+ *

+ * {@link ValueChangeEvent}s must not be emitted for internal value + * changes during a transaction. If the value changes as a result of + * {@link #commit()}, a {@link ValueChangeEvent} should be emitted. + *

+ */ + public void startTransaction(); + + /** + * Commits and ends the transaction that is in progress. + *

+ * If the value is changed as a result of this operation, a + * {@link ValueChangeEvent} is emitted if such are supported. + *

+ * This method has no effect if there is no transaction is in progress. + *

+ * This method must never throw an exception. + */ + public void commit(); + + /** + * Aborts and rolls back the transaction that is in progress. + *

+ * The value is reset to the value before the transaction started. No + * {@link ValueChangeEvent} is emitted as a result of this. + *

+ * This method has no effect if there is no transaction is in progress. + *

+ * This method must never throw an exception. + */ + public void rollback(); + } + + /** + * Exception object that signals that a requested Property + * modification failed because it's in read-only mode. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + @SuppressWarnings("serial") + public class ReadOnlyException extends RuntimeException { + + /** + * Constructs a new ReadOnlyException without a detail + * message. + */ + public ReadOnlyException() { + } + + /** + * Constructs a new ReadOnlyException with the specified + * detail message. + * + * @param msg + * the detail message + */ + public ReadOnlyException(String msg) { + super(msg); + } + } + + /** + * Interface implemented by the viewer classes capable of using a Property + * as a data source. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface Viewer extends Serializable { + + /** + * Sets the Property that serves as the data source of the viewer. + * + * @param newDataSource + * the new data source Property + */ + public void setPropertyDataSource(Property newDataSource); + + /** + * Gets the Property serving as the data source of the viewer. + * + * @return the Property serving as the viewers data source + */ + public Property getPropertyDataSource(); + } + + /** + * Interface implemented by the editor classes capable of editing the + * Property. + *

+ * Implementing this interface means that the Property serving as the data + * source of the editor can be modified through the editor. It does not + * restrict the editor from editing the Property internally, though if the + * Property is in a read-only mode, attempts to modify it will result in the + * ReadOnlyException being thrown. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface Editor extends Property.Viewer, Serializable { + + } + + /* Value change event */ + + /** + * An Event object specifying the Property whose value has been + * changed. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ValueChangeEvent extends Serializable { + + /** + * Retrieves the Property that has been modified. + * + * @return source Property of the event + */ + public Property getProperty(); + } + + /** + * The listener interface for receiving + * ValueChangeEvent objects. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ValueChangeListener extends Serializable { + + /** + * Notifies this listener that the Property's value has changed. + * + * @param event + * value change event object + */ + public void valueChange(Property.ValueChangeEvent event); + } + + /** + * The interface for adding and removing ValueChangeEvent + * listeners. If a Property wishes to allow other objects to receive + * ValueChangeEvent generated by it, it must implement this + * interface. + *

+ * Note : The general Java convention is not to explicitly declare that a + * class generates events, but to directly define the + * addListener and removeListener methods. That + * way the caller of these methods has no real way of finding out if the + * class really will send the events, or if it just defines the methods to + * be able to implement an interface. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ValueChangeNotifier extends Serializable { + + /** + * Registers a new value change listener for this Property. + * + * @param listener + * the new Listener to be registered + */ + public void addValueChangeListener( + Property.ValueChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #addValueChangeListener(ValueChangeListener)} + **/ + @Deprecated + public void addListener(Property.ValueChangeListener listener); + + /** + * Removes a previously registered value change listener. + * + * @param listener + * listener to be removed + */ + public void removeValueChangeListener( + Property.ValueChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeValueChangeListener(ValueChangeListener)} + **/ + @Deprecated + public void removeListener(Property.ValueChangeListener listener); + } + + /* ReadOnly Status change event */ + + /** + * An Event object specifying the Property whose read-only + * status has been changed. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ReadOnlyStatusChangeEvent extends Serializable { + + /** + * Property whose read-only state has changed. + * + * @return source Property of the event. + */ + public Property getProperty(); + } + + /** + * The listener interface for receiving + * ReadOnlyStatusChangeEvent objects. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ReadOnlyStatusChangeListener extends Serializable { + + /** + * Notifies this listener that a Property's read-only status has + * changed. + * + * @param event + * Read-only status change event object + */ + public void readOnlyStatusChange( + Property.ReadOnlyStatusChangeEvent event); + } + + /** + * The interface for adding and removing + * ReadOnlyStatusChangeEvent listeners. If a Property wishes to + * allow other objects to receive ReadOnlyStatusChangeEvent + * generated by it, it must implement this interface. + *

+ * Note : The general Java convention is not to explicitly declare that a + * class generates events, but to directly define the + * addListener and removeListener methods. That + * way the caller of these methods has no real way of finding out if the + * class really will send the events, or if it just defines the methods to + * be able to implement an interface. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ + public interface ReadOnlyStatusChangeNotifier extends Serializable { + + /** + * Registers a new read-only status change listener for this Property. + * + * @param listener + * the new Listener to be registered + */ + public void addReadOnlyStatusChangeListener( + Property.ReadOnlyStatusChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #addReadOnlyStatusChangeListener(ReadOnlyStatusChangeListener)} + **/ + @Deprecated + public void addListener(Property.ReadOnlyStatusChangeListener listener); + + /** + * Removes a previously registered read-only status change listener. + * + * @param listener + * listener to be removed + */ + public void removeReadOnlyStatusChangeListener( + Property.ReadOnlyStatusChangeListener listener); + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeReadOnlyStatusChangeListener(ReadOnlyStatusChangeListener)} + **/ + @Deprecated + public void removeListener( + Property.ReadOnlyStatusChangeListener listener); + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Validatable.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Validatable.java new file mode 100644 index 0000000000..5c75d594ba --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Validatable.java @@ -0,0 +1,130 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data; + +import java.io.Serializable; +import java.util.Collection; + +/** + *

+ * Interface for validatable objects. Defines methods to verify if the object's + * value is valid or not, and to add, remove and list registered validators of + * the object. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + * @see com.vaadin.v7.data.Validator + */ +public interface Validatable extends Serializable { + + /** + *

+ * Adds a new validator for this object. The validator's + * {@link Validator#validate(Object)} method is activated every time the + * object's value needs to be verified, that is, when the {@link #isValid()} + * method is called. This usually happens when the object's value changes. + *

+ * + * @param validator + * the new validator + */ + void addValidator(Validator validator); + + /** + *

+ * Removes a previously registered validator from the object. The specified + * validator is removed from the object and its validate method + * is no longer called in {@link #isValid()}. + *

+ * + * @param validator + * the validator to remove + */ + void removeValidator(Validator validator); + + /** + * Removes all validators from this object, as if + * {@link #removeValidator(Validator) removeValidator} was called for each + * registered validator. + */ + void removeAllValidators(); + + /** + *

+ * Returns a collection of all validators currently registered for the + * object. The collection may be immutable. Calling + * removeValidator for this Validatable while iterating over + * the collection may be unsafe (e.g. may throw + * ConcurrentModificationException.) + *

+ * + * @return A collection of validators + */ + public Collection getValidators(); + + /** + *

+ * Tests the current value of the object against all registered validators. + * The registered validators are iterated and for each the + * {@link Validator#validate(Object)} method is called. If any validator + * throws the {@link Validator.InvalidValueException} this method returns + * false. + *

+ * + * @return true if the registered validators concur that the + * value is valid, false otherwise + */ + public boolean isValid(); + + /** + *

+ * Checks the validity of the validatable. If the validatable is valid this + * method should do nothing, and if it's not valid, it should throw + * Validator.InvalidValueException + *

+ * + * @throws Validator.InvalidValueException + * if the value is not valid + */ + public void validate() throws Validator.InvalidValueException; + + /** + *

+ * Checks the validabtable object accept invalid values.The default value is + * true. + *

+ * + */ + public boolean isInvalidAllowed(); + + /** + *

+ * Should the validabtable object accept invalid values. Supporting this + * configuration possibility is optional. By default invalid values are + * allowed. + *

+ * + * @param invalidValueAllowed + * + * @throws UnsupportedOperationException + * if the setInvalidAllowed is not supported. + */ + public void setInvalidAllowed(boolean invalidValueAllowed) + throws UnsupportedOperationException; + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java new file mode 100644 index 0000000000..a6ad0331ed --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java @@ -0,0 +1,198 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data; + +import java.io.Serializable; + +import com.vaadin.server.AbstractErrorMessage; +import com.vaadin.server.AbstractErrorMessage.ContentMode; +import com.vaadin.server.ErrorMessage; +import com.vaadin.server.ErrorMessage.ErrorLevel; +import com.vaadin.server.ErrorMessageProducer; +import com.vaadin.server.UserError; +import com.vaadin.server.VaadinServlet; + +/** + * Interface that implements a method for validating if an {@link Object} is + * valid or not. + *

+ * Implementors of this class can be added to any + * {@link com.vaadin.v7.data.Validatable Validatable} implementor to verify its + * value. + *

+ *

+ * {@link #validate(Object)} can be used to check if a value is valid. An + * {@link InvalidValueException} with an appropriate validation error message is + * thrown if the value is not valid. + *

+ *

+ * Validators must not have any side effects. + *

+ *

+ * Since Vaadin 7, the method isValid(Object) does not exist in the interface - + * {@link #validate(Object)} should be used instead, and the exception caught + * where applicable. Concrete classes implementing {@link Validator} can still + * internally implement and use isValid(Object) for convenience or to ease + * migration from earlier Vaadin versions. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ +public interface Validator extends Serializable { + + /** + * Checks the given value against this validator. If the value is valid the + * method does nothing. If the value is invalid, an + * {@link InvalidValueException} is thrown. + * + * @param value + * the value to check + * @throws Validator.InvalidValueException + * if the value is invalid + */ + public void validate(Object value) throws Validator.InvalidValueException; + + /** + * Exception that is thrown by a {@link Validator} when a value is invalid. + * + *

+ * The default implementation of InvalidValueException does not support HTML + * in error messages. To enable HTML support, override + * {@link #getHtmlMessage()} and use the subclass in validators. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ + @SuppressWarnings("serial") + public class InvalidValueException extends RuntimeException + implements ErrorMessageProducer { + + /** + * Array of one or more validation errors that are causing this + * validation error. + */ + private InvalidValueException[] causes = null; + + /** + * Constructs a new {@code InvalidValueException} with the specified + * message. + * + * @param message + * The detail message of the problem. + */ + public InvalidValueException(String message) { + this(message, new InvalidValueException[] {}); + } + + /** + * Constructs a new {@code InvalidValueException} with a set of causing + * validation exceptions. The causing validation exceptions are included + * when the exception is painted to the client. + * + * @param message + * The detail message of the problem. + * @param causes + * One or more {@code InvalidValueException}s that caused + * this exception. + */ + public InvalidValueException(String message, + InvalidValueException... causes) { + super(message); + if (causes == null) { + throw new NullPointerException( + "Possible causes array must not be null"); + } + + this.causes = causes; + } + + /** + * Check if the error message should be hidden. + * + * An empty (null or "") message is invisible unless it contains nested + * exceptions that are visible. + * + * @return true if the error message should be hidden, false otherwise + */ + public boolean isInvisible() { + String msg = getMessage(); + if (msg != null && msg.length() > 0) { + return false; + } + if (causes != null) { + for (int i = 0; i < causes.length; i++) { + if (!causes[i].isInvisible()) { + return false; + } + } + } + return true; + } + + /** + * Returns the message of the error in HTML. + * + * Note that this API may change in future versions. + */ + public String getHtmlMessage() { + return VaadinServlet.safeEscapeForHtml(getLocalizedMessage()); + } + + /** + * Returns the {@code InvalidValueExceptions} that caused this + * exception. + * + * @return An array containing the {@code InvalidValueExceptions} that + * caused this exception. Returns an empty array if this + * exception was not caused by other exceptions. + */ + public InvalidValueException[] getCauses() { + return causes; + } + + @Override + public ErrorMessage getErrorMessage() { + UserError error = new UserError(getHtmlMessage(), ContentMode.HTML, + ErrorLevel.ERROR); + for (Validator.InvalidValueException nestedException : getCauses()) { + error.addCause(AbstractErrorMessage + .getErrorMessageForException(nestedException)); + } + return error; + } + + } + + /** + * A specific type of {@link InvalidValueException} that indicates that + * validation failed because the value was empty. What empty means is up to + * the thrower. + * + * @author Vaadin Ltd. + * @since 5.3.0 + */ + @SuppressWarnings("serial") + public class EmptyValueException extends Validator.InvalidValueException { + + public EmptyValueException(String message) { + super(message); + } + + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java new file mode 100644 index 0000000000..33d22777ad --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java @@ -0,0 +1,270 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.logging.Logger; + +import com.vaadin.v7.data.Property; + +/** + * Abstract base class for {@link Property} implementations. + * + * Handles listener management for {@link ValueChangeListener}s and + * {@link ReadOnlyStatusChangeListener}s. + * + * @since 6.6 + */ +public abstract class AbstractProperty implements Property, + Property.ValueChangeNotifier, Property.ReadOnlyStatusChangeNotifier { + + /** + * List of listeners who are interested in the read-only status changes of + * the Property + */ + private LinkedList readOnlyStatusChangeListeners = null; + + /** + * List of listeners who are interested in the value changes of the Property + */ + private LinkedList valueChangeListeners = null; + + /** + * Is the Property read-only? + */ + private boolean readOnly; + + /** + * {@inheritDoc} + * + * Override for additional restrictions on what is considered a read-only + * property. + */ + @Override + public boolean isReadOnly() { + return readOnly; + } + + @Override + public void setReadOnly(boolean newStatus) { + boolean oldStatus = isReadOnly(); + readOnly = newStatus; + if (oldStatus != isReadOnly()) { + fireReadOnlyStatusChange(); + } + } + + /* Events */ + + /** + * An Event object specifying the Property whose read-only + * status has been changed. + */ + protected static class ReadOnlyStatusChangeEvent + extends java.util.EventObject + implements Property.ReadOnlyStatusChangeEvent { + + /** + * Constructs a new read-only status change event for this object. + * + * @param source + * source object of the event. + */ + protected ReadOnlyStatusChangeEvent(Property source) { + super(source); + } + + /** + * Gets the Property whose read-only state has changed. + * + * @return source Property of the event. + */ + @Override + public Property getProperty() { + return (Property) getSource(); + } + + } + + /** + * Registers a new read-only status change listener for this Property. + * + * @param listener + * the new Listener to be registered. + */ + @Override + public void addReadOnlyStatusChangeListener( + Property.ReadOnlyStatusChangeListener listener) { + if (readOnlyStatusChangeListeners == null) { + readOnlyStatusChangeListeners = new LinkedList(); + } + readOnlyStatusChangeListeners.add(listener); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addReadOnlyStatusChangeListener(com.vaadin.v7.data.Property.ReadOnlyStatusChangeListener)} + **/ + @Override + @Deprecated + public void addListener(Property.ReadOnlyStatusChangeListener listener) { + addReadOnlyStatusChangeListener(listener); + } + + /** + * Removes a previously registered read-only status change listener. + * + * @param listener + * the listener to be removed. + */ + @Override + public void removeReadOnlyStatusChangeListener( + Property.ReadOnlyStatusChangeListener listener) { + if (readOnlyStatusChangeListeners != null) { + readOnlyStatusChangeListeners.remove(listener); + } + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeReadOnlyStatusChangeListener(com.vaadin.v7.data.Property.ReadOnlyStatusChangeListener)} + **/ + @Override + @Deprecated + public void removeListener(Property.ReadOnlyStatusChangeListener listener) { + removeReadOnlyStatusChangeListener(listener); + } + + /** + * Sends a read only status change event to all registered listeners. + */ + protected void fireReadOnlyStatusChange() { + if (readOnlyStatusChangeListeners != null) { + final Object[] l = readOnlyStatusChangeListeners.toArray(); + final Property.ReadOnlyStatusChangeEvent event = new ReadOnlyStatusChangeEvent( + this); + for (int i = 0; i < l.length; i++) { + ((Property.ReadOnlyStatusChangeListener) l[i]) + .readOnlyStatusChange(event); + } + } + } + + /** + * An Event object specifying the Property whose value has been + * changed. + */ + private static class ValueChangeEvent extends java.util.EventObject + implements Property.ValueChangeEvent { + + /** + * Constructs a new value change event for this object. + * + * @param source + * source object of the event. + */ + protected ValueChangeEvent(Property source) { + super(source); + } + + /** + * Gets the Property whose value has changed. + * + * @return source Property of the event. + */ + @Override + public Property getProperty() { + return (Property) getSource(); + } + + } + + @Override + public void addValueChangeListener(ValueChangeListener listener) { + if (valueChangeListeners == null) { + valueChangeListeners = new LinkedList(); + } + valueChangeListeners.add(listener); + + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addValueChangeListener(com.vaadin.v7.data.Property.ValueChangeListener)} + **/ + @Override + @Deprecated + public void addListener(ValueChangeListener listener) { + addValueChangeListener(listener); + } + + @Override + public void removeValueChangeListener(ValueChangeListener listener) { + if (valueChangeListeners != null) { + valueChangeListeners.remove(listener); + } + + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeValueChangeListener(com.vaadin.v7.data.Property.ValueChangeListener)} + **/ + @Override + @Deprecated + public void removeListener(ValueChangeListener listener) { + removeValueChangeListener(listener); + } + + /** + * Sends a value change event to all registered listeners. + */ + protected void fireValueChange() { + if (valueChangeListeners != null) { + final Object[] l = valueChangeListeners.toArray(); + final Property.ValueChangeEvent event = new ValueChangeEvent(this); + for (int i = 0; i < l.length; i++) { + ((Property.ValueChangeListener) l[i]).valueChange(event); + } + } + } + + public Collection getListeners(Class eventType) { + if (Property.ValueChangeEvent.class.isAssignableFrom(eventType)) { + if (valueChangeListeners == null) { + return Collections.EMPTY_LIST; + } else { + return Collections.unmodifiableCollection(valueChangeListeners); + } + } else if (Property.ReadOnlyStatusChangeEvent.class + .isAssignableFrom(eventType)) { + if (readOnlyStatusChangeListeners == null) { + return Collections.EMPTY_LIST; + } else { + return Collections + .unmodifiableCollection(readOnlyStatusChangeListeners); + } + } + + return Collections.EMPTY_LIST; + } + + private static Logger getLogger() { + return Logger.getLogger(AbstractProperty.class.getName()); + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/ListSet.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ListSet.java new file mode 100644 index 0000000000..2fd182238d --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ListSet.java @@ -0,0 +1,276 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +/** + * ListSet is an internal Vaadin class which implements a combination of a List + * and a Set. The main purpose of this class is to provide a list with a fast + * {@link #contains(Object)} method. Each inserted object must by unique (as + * specified by {@link #equals(Object)}). The {@link #set(int, Object)} method + * allows duplicates because of the way {@link Collections#sort(java.util.List)} + * works. + * + * This class is subject to change and should not be used outside Vaadin core. + */ +public class ListSet extends ArrayList { + private HashSet itemSet = null; + + /** + * Contains a map from an element to the number of duplicates it has. Used + * to temporarily allow duplicates in the list. + */ + private HashMap duplicates = new HashMap(); + + public ListSet() { + super(); + itemSet = new HashSet(); + } + + public ListSet(Collection c) { + super(c); + itemSet = new HashSet(c.size()); + itemSet.addAll(c); + } + + public ListSet(int initialCapacity) { + super(initialCapacity); + itemSet = new HashSet(initialCapacity); + } + + // Delegate contains operations to the set + @Override + public boolean contains(Object o) { + return itemSet.contains(o); + } + + @Override + public boolean containsAll(Collection c) { + return itemSet.containsAll(c); + } + + // Methods for updating the set when the list is updated. + @Override + public boolean add(E e) { + if (contains(e)) { + // Duplicates are not allowed + return false; + } + + if (super.add(e)) { + itemSet.add(e); + return true; + } else { + return false; + } + } + + /** + * Works as java.util.ArrayList#add(int, java.lang.Object) but returns + * immediately if the element is already in the ListSet. + */ + @Override + public void add(int index, E element) { + if (contains(element)) { + // Duplicates are not allowed + return; + } + + super.add(index, element); + itemSet.add(element); + } + + @Override + public boolean addAll(Collection c) { + boolean modified = false; + Iterator i = c.iterator(); + while (i.hasNext()) { + E e = i.next(); + if (contains(e)) { + continue; + } + + if (add(e)) { + itemSet.add(e); + modified = true; + } + } + return modified; + } + + @Override + public boolean addAll(int index, Collection c) { + ensureCapacity(size() + c.size()); + + boolean modified = false; + Iterator i = c.iterator(); + while (i.hasNext()) { + E e = i.next(); + if (contains(e)) { + continue; + } + + add(index++, e); + itemSet.add(e); + modified = true; + } + + return modified; + } + + @Override + public void clear() { + super.clear(); + itemSet.clear(); + } + + @Override + public int indexOf(Object o) { + if (!contains(o)) { + return -1; + } + + return super.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + if (!contains(o)) { + return -1; + } + + return super.lastIndexOf(o); + } + + @Override + public E remove(int index) { + E e = super.remove(index); + + if (e != null) { + itemSet.remove(e); + } + + return e; + } + + @Override + public boolean remove(Object o) { + if (super.remove(o)) { + itemSet.remove(o); + return true; + } else { + return false; + } + } + + @Override + protected void removeRange(int fromIndex, int toIndex) { + HashSet toRemove = new HashSet(); + for (int idx = fromIndex; idx < toIndex; idx++) { + toRemove.add(get(idx)); + } + super.removeRange(fromIndex, toIndex); + itemSet.removeAll(toRemove); + } + + @Override + public E set(int index, E element) { + if (contains(element)) { + // Element already exist in the list + if (get(index) == element) { + // At the same position, nothing to be done + return element; + } else { + // Adding at another position. We assume this is a sort + // operation and temporarily allow it. + + // We could just remove (null) the old element and keep the list + // unique. This would require finding the index of the old + // element (indexOf(element)) which is not a fast operation in a + // list. So we instead allow duplicates temporarily. + addDuplicate(element); + } + } + + E old = super.set(index, element); + removeFromSet(old); + itemSet.add(element); + + return old; + } + + /** + * Removes "e" from the set if it no longer exists in the list. + * + * @param e + */ + private void removeFromSet(E e) { + Integer dupl = duplicates.get(e); + if (dupl != null) { + // A duplicate was present so we only decrement the duplicate count + // and continue + if (dupl == 1) { + // This is what always should happen. A sort sets the items one + // by one, temporarily breaking the uniqueness requirement. + duplicates.remove(e); + } else { + duplicates.put(e, dupl - 1); + } + } else { + // The "old" value is no longer in the list. + itemSet.remove(e); + } + + } + + /** + * Marks the "element" can be found more than once from the list. Allowed in + * {@link #set(int, Object)} to make sorting work. + * + * @param element + */ + private void addDuplicate(E element) { + Integer nr = duplicates.get(element); + if (nr == null) { + nr = 1; + } else { + nr++; + } + + /* + * Store the number of duplicates of this element so we know later on if + * we should remove an element from the set or if it was a duplicate (in + * removeFromSet) + */ + duplicates.put(element, nr); + + } + + @SuppressWarnings("unchecked") + @Override + public Object clone() { + ListSet v = (ListSet) super.clone(); + v.itemSet = new HashSet(itemSet); + return v; + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java new file mode 100644 index 0000000000..86fb0ae40d --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java @@ -0,0 +1,774 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import static com.vaadin.util.ReflectTools.convertPrimitiveType; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.vaadin.shared.util.SharedUtil; +import com.vaadin.util.SerializerHelper; +import com.vaadin.v7.data.Property; + +/** + *

+ * Proxy class for creating Properties from pairs of getter and setter methods + * of a Bean property. An instance of this class can be thought as having been + * attached to a field of an object. Accessing the object through the Property + * interface directly manipulates the underlying field. + *

+ * + *

+ * It's assumed that the return value returned by the getter method is + * assignable to the type of the property, and the setter method parameter is + * assignable to that value. + *

+ * + *

+ * A valid getter method must always be available, but instance of this class + * can be constructed with a null setter method in which case the + * resulting MethodProperty is read-only. + *

+ * + *

+ * MethodProperty implements Property.ValueChangeNotifier, but does not + * automatically know whether or not the getter method will actually return a + * new value - value change listeners are always notified when setValue is + * called, without verifying what the getter returns. + *

+ * + * @author Vaadin Ltd. + * @since 3.0 + */ +@SuppressWarnings("serial") +public class MethodProperty extends AbstractProperty { + + /** + * The object that includes the property the MethodProperty is bound to. + */ + private transient Object instance; + + /** + * Argument arrays for the getter and setter methods. + */ + private transient Object[] setArgs, getArgs; + + /** + * The getter and setter methods. + */ + private transient Method setMethod, getMethod; + + /** + * Index of the new value in the argument list for the setter method. If the + * setter method requires several parameters, this index tells which one is + * the actual value to change. + */ + private int setArgumentIndex; + + /** + * Type of the property. + */ + private transient Class type; + + private static final Object[] DEFAULT_GET_ARGS = new Object[0]; + + private static final Object[] DEFAULT_SET_ARGS = new Object[1]; + + /* Special serialization to handle method references */ + private void writeObject(java.io.ObjectOutputStream out) + throws IOException { + out.defaultWriteObject(); + SerializerHelper.writeClass(out, type); + out.writeObject(instance); + out.writeObject(setArgs); + out.writeObject(getArgs); + if (setMethod != null) { + out.writeObject(setMethod.getName()); + SerializerHelper.writeClassArray(out, + setMethod.getParameterTypes()); + } else { + out.writeObject(null); + out.writeObject(null); + } + if (getMethod != null) { + out.writeObject(getMethod.getName()); + SerializerHelper.writeClassArray(out, + getMethod.getParameterTypes()); + } else { + out.writeObject(null); + out.writeObject(null); + } + } + + /* Special serialization to handle method references */ + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + try { + @SuppressWarnings("unchecked") + // business assumption; type parameters not checked at runtime + Class class1 = (Class) SerializerHelper.readClass(in); + type = class1; + instance = in.readObject(); + Object[] setArgs = (Object[]) in.readObject(); + Object[] getArgs = (Object[]) in.readObject(); + setArguments(getArgs, setArgs, setArgumentIndex); + String name = (String) in.readObject(); + Class[] paramTypes = SerializerHelper.readClassArray(in); + if (instance != null && name != null) { + setMethod = instance.getClass().getMethod(name, paramTypes); + } else { + setMethod = null; + } + + name = (String) in.readObject(); + paramTypes = SerializerHelper.readClassArray(in); + if (instance != null && name != null) { + getMethod = instance.getClass().getMethod(name, paramTypes); + } else { + getMethod = null; + } + } catch (SecurityException e) { + getLogger().log(Level.SEVERE, "Internal deserialization error", e); + } catch (NoSuchMethodException e) { + getLogger().log(Level.SEVERE, "Internal deserialization error", e); + } + } + + /** + *

+ * Creates a new instance of MethodProperty from a named bean + * property. This constructor takes an object and the name of a bean + * property and initializes itself with the accessor methods for the + * property. + *

+ *

+ * The getter method of a MethodProperty instantiated with this + * constructor will be called with no arguments, and the setter method with + * only the new value as the sole argument. + *

+ * + *

+ * If the setter method is unavailable, the resulting + * MethodProperty will be read-only, otherwise it will be + * read-write. + *

+ * + *

+ * Method names are constructed from the bean property by adding + * get/is/are/set prefix and capitalising the first character in the name of + * the given bean property. + *

+ * + * @param instance + * the object that includes the property. + * @param beanPropertyName + * the name of the property to bind to. + */ + @SuppressWarnings("unchecked") + public MethodProperty(Object instance, String beanPropertyName) { + + final Class beanClass = instance.getClass(); + + // Assure that the first letter is upper cased (it is a common + // mistake to write firstName, not FirstName). + beanPropertyName = SharedUtil.capitalize(beanPropertyName); + + // Find the get method + getMethod = null; + try { + getMethod = initGetterMethod(beanPropertyName, beanClass); + } catch (final java.lang.NoSuchMethodException ignored) { + throw new MethodException(this, + "Bean property " + beanPropertyName + " can not be found"); + } + + // In case the get method is found, resolve the type + Class returnType = getMethod.getReturnType(); + + // Finds the set method + setMethod = null; + try { + setMethod = beanClass.getMethod("set" + beanPropertyName, + new Class[] { returnType }); + } catch (final java.lang.NoSuchMethodException skipped) { + } + + // Gets the return type from get method + if (returnType.isPrimitive()) { + type = (Class) convertPrimitiveType(returnType); + if (type.isPrimitive()) { + throw new MethodException(this, + "Bean property " + beanPropertyName + + " getter return type must not be void"); + } + } else { + type = (Class) returnType; + } + + setArguments(DEFAULT_GET_ARGS, DEFAULT_SET_ARGS, 0); + this.instance = instance; + } + + /** + *

+ * Creates a new instance of MethodProperty from named getter + * and setter methods. The getter method of a MethodProperty + * instantiated with this constructor will be called with no arguments, and + * the setter method with only the new value as the sole argument. + *

+ * + *

+ * If the setter method is null, the resulting + * MethodProperty will be read-only, otherwise it will be + * read-write. + *

+ * + * @param type + * the type of the property. + * @param instance + * the object that includes the property. + * @param getMethodName + * the name of the getter method. + * @param setMethodName + * the name of the setter method. + * + */ + public MethodProperty(Class type, Object instance, + String getMethodName, String setMethodName) { + this(type, instance, getMethodName, setMethodName, new Object[] {}, + new Object[] { null }, 0); + } + + /** + *

+ * Creates a new instance of MethodProperty with the getter and + * setter methods. The getter method of a MethodProperty + * instantiated with this constructor will be called with no arguments, and + * the setter method with only the new value as the sole argument. + *

+ * + *

+ * If the setter method is null, the resulting + * MethodProperty will be read-only, otherwise it will be + * read-write. + *

+ * + * @param type + * the type of the property. + * @param instance + * the object that includes the property. + * @param getMethod + * the getter method. + * @param setMethod + * the setter method. + */ + public MethodProperty(Class type, Object instance, + Method getMethod, Method setMethod) { + this(type, instance, getMethod, setMethod, new Object[] {}, + new Object[] { null }, 0); + } + + /** + *

+ * Creates a new instance of MethodProperty from named getter + * and setter methods and argument lists. The getter method of a + * MethodProperty instantiated with this constructor will be + * called with the getArgs as arguments. The setArgs will be used as the + * arguments for the setter method, though the argument indexed by the + * setArgumentIndex will be replaced with the argument passed to the + * {@link #setValue(Object newValue)} method. + *

+ * + *

+ * For example, if the setArgs contains A, + * B and C, and setArgumentIndex = + * 1, the call methodProperty.setValue(X) would result + * in the setter method to be called with the parameter set of + * {A, X, C} + *

+ * + * @param type + * the type of the property. + * @param instance + * the object that includes the property. + * @param getMethodName + * the name of the getter method. + * @param setMethodName + * the name of the setter method. + * @param getArgs + * the fixed argument list to be passed to the getter method. + * @param setArgs + * the fixed argument list to be passed to the setter method. + * @param setArgumentIndex + * the index of the argument in setArgs to be + * replaced with newValue when + * {@link #setValue(Object newValue)} is called. + */ + @SuppressWarnings("unchecked") + public MethodProperty(Class type, Object instance, + String getMethodName, String setMethodName, Object[] getArgs, + Object[] setArgs, int setArgumentIndex) { + + // Check the setargs and setargs index + if (setMethodName != null && setArgs == null) { + throw new IndexOutOfBoundsException("The setArgs can not be null"); + } + if (setMethodName != null && (setArgumentIndex < 0 + || setArgumentIndex >= setArgs.length)) { + throw new IndexOutOfBoundsException( + "The setArgumentIndex must be >= 0 and < setArgs.length"); + } + + // Set type + this.type = type; + + // Find set and get -methods + final Method[] m = instance.getClass().getMethods(); + + // Finds get method + boolean found = false; + for (int i = 0; i < m.length; i++) { + + // Tests the name of the get Method + if (!m[i].getName().equals(getMethodName)) { + + // name does not match, try next method + continue; + } + + // Tests return type + if (!type.equals(m[i].getReturnType())) { + continue; + } + + // Tests the parameter types + final Class[] c = m[i].getParameterTypes(); + if (c.length != getArgs.length) { + + // not the right amount of parameters, try next method + continue; + } + int j = 0; + while (j < c.length) { + if (getArgs[j] != null + && !c[j].isAssignableFrom(getArgs[j].getClass())) { + + // parameter type does not match, try next method + break; + } + j++; + } + if (j == c.length) { + + // all paramteters matched + if (found == true) { + throw new MethodException(this, + "Could not uniquely identify " + getMethodName + + "-method"); + } else { + found = true; + getMethod = m[i]; + } + } + } + if (found != true) { + throw new MethodException(this, + "Could not find " + getMethodName + "-method"); + } + + // Finds set method + if (setMethodName != null) { + + // Finds setMethod + found = false; + for (int i = 0; i < m.length; i++) { + + // Checks name + if (!m[i].getName().equals(setMethodName)) { + + // name does not match, try next method + continue; + } + + // Checks parameter compatibility + final Class[] c = m[i].getParameterTypes(); + if (c.length != setArgs.length) { + + // not the right amount of parameters, try next method + continue; + } + int j = 0; + while (j < c.length) { + if (setArgs[j] != null + && !c[j].isAssignableFrom(setArgs[j].getClass())) { + + // parameter type does not match, try next method + break; + } else if (j == setArgumentIndex && !c[j].equals(type)) { + + // Property type is not the same as setArg type + break; + } + j++; + } + if (j == c.length) { + + // all parameters match + if (found == true) { + throw new MethodException(this, + "Could not identify unique " + setMethodName + + "-method"); + } else { + found = true; + setMethod = m[i]; + } + } + } + if (found != true) { + throw new MethodException(this, + "Could not identify " + setMethodName + "-method"); + } + } + + // Gets the return type from get method + this.type = (Class) convertPrimitiveType(type); + + setArguments(getArgs, setArgs, setArgumentIndex); + this.instance = instance; + } + + /** + *

+ * Creates a new instance of MethodProperty from the getter and + * setter methods, and argument lists. + *

+ *

+ * This constructor behaves exactly like + * {@link #MethodProperty(Class type, Object instance, String getMethodName, String setMethodName, Object [] getArgs, Object [] setArgs, int setArgumentIndex)} + * except that instead of names of the getter and setter methods this + * constructor is given the actual methods themselves. + *

+ * + * @param type + * the type of the property. + * @param instance + * the object that includes the property. + * @param getMethod + * the getter method. + * @param setMethod + * the setter method. + * @param getArgs + * the fixed argument list to be passed to the getter method. + * @param setArgs + * the fixed argument list to be passed to the setter method. + * @param setArgumentIndex + * the index of the argument in setArgs to be + * replaced with newValue when + * {@link #setValue(Object newValue)} is called. + */ + @SuppressWarnings("unchecked") + // cannot use "Class" because of automatic primitive type + // conversions + public MethodProperty(Class type, Object instance, Method getMethod, + Method setMethod, Object[] getArgs, Object[] setArgs, + int setArgumentIndex) { + + if (getMethod == null) { + throw new MethodException(this, + "Property GET-method cannot not be null: " + type); + } + + if (setMethod != null) { + if (setArgs == null) { + throw new IndexOutOfBoundsException( + "The setArgs can not be null"); + } + if (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length) { + throw new IndexOutOfBoundsException( + "The setArgumentIndex must be >= 0 and < setArgs.length"); + } + } + + // Gets the return type from get method + Class convertedType = (Class) convertPrimitiveType( + type); + + this.getMethod = getMethod; + this.setMethod = setMethod; + setArguments(getArgs, setArgs, setArgumentIndex); + this.instance = instance; + this.type = convertedType; + } + + /** + * Find a getter method for a property (getXyz(), isXyz() or areXyz()). + * + * @param propertyName + * name of the property + * @param beanClass + * class in which to look for the getter methods + * @return Method + * @throws NoSuchMethodException + * if no getter found + */ + static Method initGetterMethod(String propertyName, + final Class beanClass) throws NoSuchMethodException { + propertyName = SharedUtil.capitalize(propertyName); + + Method getMethod = null; + try { + getMethod = beanClass.getMethod("get" + propertyName, + new Class[] {}); + } catch (final java.lang.NoSuchMethodException ignored) { + try { + getMethod = beanClass.getMethod("is" + propertyName, + new Class[] {}); + } catch (final java.lang.NoSuchMethodException ignoredAsWell) { + getMethod = beanClass.getMethod("are" + propertyName, + new Class[] {}); + } + } + return getMethod; + } + + /** + * Returns the type of the Property. The methods getValue and + * setValue must be compatible with this type: one must be able + * to safely cast the value returned from getValue to the given + * type and pass any variable assignable to this type as an argument to + * setValue. + * + * @return type of the Property + */ + @Override + public final Class getType() { + return type; + } + + /** + * Tests if the object is in read-only mode. In read-only mode calls to + * setValue will throw ReadOnlyException and will + * not modify the value of the Property. + * + * @return true if the object is in read-only mode, + * false if it's not + */ + @Override + public boolean isReadOnly() { + return super.isReadOnly() || (setMethod == null); + } + + /** + * Gets the value stored in the Property. The value is resolved by calling + * the specified getter method with the argument specified at instantiation. + * + * @return the value of the Property + */ + @Override + public T getValue() { + try { + if (instance == null) { + return null; + } else { + return (T) getMethod.invoke(instance, getArgs); + } + } catch (final Throwable e) { + throw new MethodException(this, e); + } + } + + /** + *

+ * Sets the setter method and getter method argument lists. + *

+ * + * @param getArgs + * the fixed argument list to be passed to the getter method. + * @param setArgs + * the fixed argument list to be passed to the setter method. + * @param setArgumentIndex + * the index of the argument in setArgs to be + * replaced with newValue when + * {@link #setValue(Object newValue)} is called. + */ + public void setArguments(Object[] getArgs, Object[] setArgs, + int setArgumentIndex) { + if (getArgs.length == 0) { + this.getArgs = DEFAULT_GET_ARGS; + } else { + this.getArgs = Arrays.copyOf(getArgs, getArgs.length); + } + if (Arrays.equals(setArgs, DEFAULT_SET_ARGS)) { + this.setArgs = DEFAULT_SET_ARGS; + } else { + this.setArgs = Arrays.copyOf(setArgs, setArgs.length); + } + this.setArgumentIndex = setArgumentIndex; + } + + /** + * Sets the value of the property. + * + * Note that since Vaadin 7, no conversions are performed and the value must + * be of the correct type. + * + * @param newValue + * the New value of the property. + * @throws Property.ReadOnlyException + * if the object is in read-only mode. + * @see #invokeSetMethod(Object) + */ + @Override + public void setValue(T newValue) throws Property.ReadOnlyException { + + // Checks the mode + if (isReadOnly()) { + throw new Property.ReadOnlyException(); + } + + invokeSetMethod(newValue); + fireValueChange(); + } + + /** + * Internal method to actually call the setter method of the wrapped + * property. + * + * @param value + */ + protected void invokeSetMethod(T value) { + + try { + // Construct a temporary argument array only if needed + if (setArgs.length == 1) { + setMethod.invoke(instance, new Object[] { value }); + } else { + + // Sets the value to argument array + final Object[] args = new Object[setArgs.length]; + for (int i = 0; i < setArgs.length; i++) { + args[i] = (i == setArgumentIndex) ? value : setArgs[i]; + } + setMethod.invoke(instance, args); + } + } catch (final InvocationTargetException e) { + final Throwable targetException = e.getTargetException(); + throw new MethodException(this, targetException); + } catch (final Exception e) { + throw new MethodException(this, e); + } + } + + /** + * Exception object that signals that there were problems + * calling or finding the specified getter or setter methods of the + * property. + * + * @author Vaadin Ltd. + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + // Exceptions cannot be parameterized, ever. + public static class MethodException extends RuntimeException { + + /** + * The method property from which the exception originates from + */ + private final Property property; + + /** + * Cause of the method exception + */ + private Throwable cause; + + /** + * Constructs a new MethodException with the specified + * detail message. + * + * @param property + * the property. + * @param msg + * the detail message. + */ + public MethodException(Property property, String msg) { + super(msg); + this.property = property; + } + + /** + * Constructs a new MethodException from another exception. + * + * @param property + * the property. + * @param cause + * the cause of the exception. + */ + public MethodException(Property property, Throwable cause) { + this.property = property; + this.cause = cause; + } + + /** + * @see java.lang.Throwable#getCause() + */ + @Override + public Throwable getCause() { + return cause; + } + + /** + * Gets the method property this exception originates from. + * + * @return MethodProperty or null if not a valid MethodProperty + */ + public MethodProperty getMethodProperty() { + return (property instanceof MethodProperty) + ? (MethodProperty) property : null; + } + + /** + * Gets the method property this exception originates from. + * + * @return Property from which the exception originates + */ + public Property getProperty() { + return property; + } + } + + /** + * Sends a value change event to all registered listeners. + * + * Public for backwards compatibility, visibility may be reduced in future + * versions. + */ + @Override + public void fireValueChange() { + super.fireValueChange(); + } + + private static final Logger getLogger() { + return Logger.getLogger(MethodProperty.class.getName()); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java new file mode 100644 index 0000000000..dfffb5b189 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java @@ -0,0 +1,148 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.vaadin.util.ReflectTools; +import com.vaadin.util.SerializerHelper; +import com.vaadin.v7.data.Property; + +/** + * Property descriptor that is able to create simple {@link MethodProperty} + * instances for a bean, using given accessors. + * + * @param + * bean type + * + * @since 6.6 + */ +public class MethodPropertyDescriptor + implements VaadinPropertyDescriptor { + + private final String name; + private Class propertyType; + private transient Method readMethod; + private transient Method writeMethod; + + /** + * Creates a property descriptor that can create MethodProperty instances to + * access the underlying bean property. + * + * @param name + * of the property + * @param propertyType + * type (class) of the property + * @param readMethod + * getter {@link Method} for the property + * @param writeMethod + * setter {@link Method} for the property or null if read-only + * property + */ + public MethodPropertyDescriptor(String name, Class propertyType, + Method readMethod, Method writeMethod) { + this.name = name; + this.propertyType = ReflectTools.convertPrimitiveType(propertyType); + this.readMethod = readMethod; + this.writeMethod = writeMethod; + } + + /* Special serialization to handle method references */ + private void writeObject(java.io.ObjectOutputStream out) + throws IOException { + out.defaultWriteObject(); + SerializerHelper.writeClass(out, propertyType); + + if (writeMethod != null) { + out.writeObject(writeMethod.getName()); + SerializerHelper.writeClass(out, writeMethod.getDeclaringClass()); + SerializerHelper.writeClassArray(out, + writeMethod.getParameterTypes()); + } else { + out.writeObject(null); + out.writeObject(null); + out.writeObject(null); + } + + if (readMethod != null) { + out.writeObject(readMethod.getName()); + SerializerHelper.writeClass(out, readMethod.getDeclaringClass()); + SerializerHelper.writeClassArray(out, + readMethod.getParameterTypes()); + } else { + out.writeObject(null); + out.writeObject(null); + out.writeObject(null); + } + } + + /* Special serialization to handle method references */ + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + try { + @SuppressWarnings("unchecked") + // business assumption; type parameters not checked at runtime + Class class1 = (Class) SerializerHelper.readClass(in); + propertyType = ReflectTools.convertPrimitiveType(class1); + + String name = (String) in.readObject(); + Class writeMethodClass = SerializerHelper.readClass(in); + Class[] paramTypes = SerializerHelper.readClassArray(in); + if (name != null) { + writeMethod = writeMethodClass.getMethod(name, paramTypes); + } else { + writeMethod = null; + } + + name = (String) in.readObject(); + Class readMethodClass = SerializerHelper.readClass(in); + paramTypes = SerializerHelper.readClassArray(in); + if (name != null) { + readMethod = readMethodClass.getMethod(name, paramTypes); + } else { + readMethod = null; + } + } catch (SecurityException e) { + getLogger().log(Level.SEVERE, "Internal deserialization error", e); + } catch (NoSuchMethodException e) { + getLogger().log(Level.SEVERE, "Internal deserialization error", e); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public Class getPropertyType() { + return propertyType; + } + + @Override + public Property createProperty(Object bean) { + return new MethodProperty(propertyType, bean, readMethod, + writeMethod); + } + + private static final Logger getLogger() { + return Logger.getLogger(MethodPropertyDescriptor.class.getName()); + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java new file mode 100644 index 0000000000..38bf7300aa --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java @@ -0,0 +1,269 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import static com.vaadin.util.ReflectTools.convertPrimitiveType; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.vaadin.shared.util.SharedUtil; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.util.MethodProperty.MethodException; + +/** + * Nested accessor based property for a bean. + * + * The property is specified in the dotted notation, e.g. "address.street", and + * can contain multiple levels of nesting. + * + * When accessing the property value, all intermediate getters must exist and + * should return non-null values when the property value is accessed. If an + * intermediate getter returns null, a null value will be returned. + * + * @see MethodProperty + * + * @since 6.6 + */ +public class NestedMethodProperty extends AbstractProperty { + + // needed for de-serialization + private String propertyName; + + // chain of getter methods + private transient List getMethods; + /** + * The setter method. + */ + private transient Method setMethod; + + /** + * Bean instance used as a starting point for accessing the property value. + */ + private Object instance; + + private Class type; + + /* Special serialization to handle method references */ + private void writeObject(java.io.ObjectOutputStream out) + throws IOException { + out.defaultWriteObject(); + // getMethods and setMethod are reconstructed on read based on + // propertyName + } + + /* Special serialization to handle method references */ + private void readObject(java.io.ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + + initialize(instance.getClass(), propertyName); + } + + /** + * Constructs a nested method property for a given object instance. The + * property name is a dot separated string pointing to a nested property, + * e.g. "manager.address.street". + *

+ * Calling getValue will return null if any intermediate getter returns null + * + * @param instance + * top-level bean to which the property applies + * @param propertyName + * dot separated nested property name + * @throws IllegalArgumentException + * if the property name is invalid + */ + public NestedMethodProperty(Object instance, String propertyName) { + this.instance = instance; + initialize(instance.getClass(), propertyName); + } + + /** + * For internal use to deduce property type etc. without a bean instance. + * Calling {@link #setValue(Object)} or {@link #getValue()} on properties + * constructed this way is not supported. + * + * @param instanceClass + * class of the top-level bean + * @param propertyName + */ + NestedMethodProperty(Class instanceClass, String propertyName) { + instance = null; + initialize(instanceClass, propertyName); + } + + /** + * Initializes most of the internal fields based on the top-level bean + * instance and property name (dot-separated string). + * + * @param beanClass + * class of the top-level bean to which the property applies + * @param propertyName + * dot separated nested property name + * @throws IllegalArgumentException + * if the property name is invalid + */ + private void initialize(Class beanClass, String propertyName) + throws IllegalArgumentException { + + List getMethods = new ArrayList(); + + String lastSimplePropertyName = propertyName; + Class lastClass = beanClass; + + // first top-level property, then go deeper in a loop + Class propertyClass = beanClass; + String[] simplePropertyNames = propertyName.split("\\."); + if (propertyName.endsWith(".") || 0 == simplePropertyNames.length) { + throw new IllegalArgumentException( + "Invalid property name '" + propertyName + "'"); + } + for (int i = 0; i < simplePropertyNames.length; i++) { + String simplePropertyName = simplePropertyNames[i].trim(); + if (simplePropertyName.length() > 0) { + lastSimplePropertyName = simplePropertyName; + lastClass = propertyClass; + try { + Method getter = MethodProperty.initGetterMethod( + simplePropertyName, propertyClass); + propertyClass = getter.getReturnType(); + getMethods.add(getter); + } catch (final java.lang.NoSuchMethodException e) { + throw new IllegalArgumentException("Bean property '" + + simplePropertyName + "' not found", e); + } + } else { + throw new IllegalArgumentException( + "Empty or invalid bean property identifier in '" + + propertyName + "'"); + } + } + + // In case the get method is found, resolve the type + Method lastGetMethod = getMethods.get(getMethods.size() - 1); + Class type = lastGetMethod.getReturnType(); + + // Finds the set method + Method setMethod = null; + try { + // Assure that the first letter is upper cased (it is a common + // mistake to write firstName, not FirstName). + lastSimplePropertyName = SharedUtil + .capitalize(lastSimplePropertyName); + + setMethod = lastClass.getMethod("set" + lastSimplePropertyName, + new Class[] { type }); + } catch (final NoSuchMethodException skipped) { + } + + this.type = (Class) convertPrimitiveType(type); + this.propertyName = propertyName; + this.getMethods = getMethods; + this.setMethod = setMethod; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isReadOnly() { + return super.isReadOnly() || (null == setMethod); + } + + /** + * Gets the value stored in the Property. The value is resolved by calling + * the specified getter method with the argument specified at instantiation. + * + * @return the value of the Property + */ + @Override + public T getValue() { + try { + Object object = instance; + for (Method m : getMethods) { + object = m.invoke(object); + if (object == null) { + return null; + } + } + return (T) object; + } catch (final Throwable e) { + throw new MethodException(this, e); + } + } + + /** + * Sets the value of the property. The new value must be assignable to the + * type of this property. + * + * @param newValue + * the New value of the property. + * @throws Property.ReadOnlyException + * if the object is in read-only mode. + * @see #invokeSetMethod(Object) + */ + @Override + public void setValue(T newValue) throws ReadOnlyException { + // Checks the mode + if (isReadOnly()) { + throw new Property.ReadOnlyException(); + } + + invokeSetMethod(newValue); + fireValueChange(); + } + + /** + * Internal method to actually call the setter method of the wrapped + * property. + * + * @param value + */ + protected void invokeSetMethod(T value) { + try { + Object object = instance; + for (int i = 0; i < getMethods.size() - 1; i++) { + object = getMethods.get(i).invoke(object); + } + setMethod.invoke(object, new Object[] { value }); + } catch (final InvocationTargetException e) { + throw new MethodException(this, e.getTargetException()); + } catch (final Exception e) { + throw new MethodException(this, e); + } + } + + /** + * Returns an unmodifiable list of getter methods to call in sequence to get + * the property value. + * + * This API may change in future versions. + * + * @return unmodifiable list of getter methods corresponding to each segment + * of the property name + */ + protected List getGetMethods() { + return Collections.unmodifiableList(getMethods); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java new file mode 100644 index 0000000000..7bbf6253a5 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import com.vaadin.v7.data.Property; + +/** + * Property descriptor that is able to create nested property instances for a + * bean. + * + * The property is specified in the dotted notation, e.g. "address.street", and + * can contain multiple levels of nesting. + * + * @param + * bean type + * + * @since 6.6 + */ +public class NestedPropertyDescriptor + implements VaadinPropertyDescriptor { + + private final String name; + private final Class propertyType; + + /** + * Creates a property descriptor that can create MethodProperty instances to + * access the underlying bean property. + * + * @param name + * of the property in a dotted path format, e.g. "address.street" + * @param beanType + * type (class) of the top-level bean + * @throws IllegalArgumentException + * if the property name is invalid + */ + public NestedPropertyDescriptor(String name, Class beanType) + throws IllegalArgumentException { + this.name = name; + NestedMethodProperty property = new NestedMethodProperty( + beanType, name); + this.propertyType = property.getType(); + } + + @Override + public String getName() { + return name; + } + + @Override + public Class getPropertyType() { + return propertyType; + } + + @Override + public Property createProperty(BT bean) { + return new NestedMethodProperty(bean, name); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java new file mode 100644 index 0000000000..cd9f6c36c7 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java @@ -0,0 +1,142 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import com.vaadin.v7.data.Property; + +/** + * A simple data object containing one typed value. This class is a + * straightforward implementation of the the {@link com.vaadin.v7.data.Property} + * interface. + * + * @author Vaadin Ltd. + * @since 3.0 + */ +@SuppressWarnings("serial") +public class ObjectProperty extends AbstractProperty { + + /** + * The value contained by the Property. + */ + private T value; + + /** + * Data type of the Property's value. + */ + private final Class type; + + /** + * Creates a new instance of ObjectProperty with the given value. The type + * of the property is automatically initialized to be the type of the given + * value. + * + * @param value + * the Initial value of the Property. + */ + @SuppressWarnings("unchecked") + // the cast is safe, because an object of type T has class Class + public ObjectProperty(T value) { + this(value, (Class) value.getClass()); + } + + /** + * Creates a new instance of ObjectProperty with the given value and type. + * + * Since Vaadin 7, only values of the correct type are accepted, and no + * automatic conversions are performed. + * + * @param value + * the Initial value of the Property. + * @param type + * the type of the value. The value must be assignable to given + * type. + */ + public ObjectProperty(T value, Class type) { + + // Set the values + this.type = type; + setValue(value); + } + + /** + * Creates a new instance of ObjectProperty with the given value, type and + * read-only mode status. + * + * Since Vaadin 7, only the correct type of values is accepted, see + * {@link #ObjectProperty(Object, Class)}. + * + * @param value + * the Initial value of the property. + * @param type + * the type of the value. value must be assignable + * to this type. + * @param readOnly + * Sets the read-only mode. + */ + public ObjectProperty(T value, Class type, boolean readOnly) { + this(value, type); + setReadOnly(readOnly); + } + + /** + * Returns the type of the ObjectProperty. The methods getValue + * and setValue must be compatible with this type: one must be + * able to safely cast the value returned from getValue to the + * given type and pass any variable assignable to this type as an argument + * to setValue. + * + * @return type of the Property + */ + @Override + public final Class getType() { + return type; + } + + /** + * Gets the value stored in the Property. + * + * @return the value stored in the Property + */ + @Override + public T getValue() { + return value; + } + + /** + * Sets the value of the property. + * + * Note that since Vaadin 7, no conversions are performed and the value must + * be of the correct type. + * + * @param newValue + * the New value of the property. + * @throws Property.ReadOnlyException + * if the object is in read-only mode + */ + @Override + public void setValue(T newValue) throws Property.ReadOnlyException { + + // Checks the mode + if (isReadOnly()) { + throw new Property.ReadOnlyException(); + } + + this.value = newValue; + + fireValueChange(); + } +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java new file mode 100644 index 0000000000..c95f97a1f1 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java @@ -0,0 +1,257 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.util.converter.Converter; + +/** + * Formatting proxy for a {@link Property}. + * + *

+ * This class can be used to implement formatting for any type of Property + * datasources. The idea is to connect this as proxy between UI component and + * the original datasource. + *

+ * + *

+ * For example + *

textfield.setPropertyDataSource(new PropertyFormatter(property) {
+            public String format(Object value) {
+                return ((Double) value).toString() + "000000000";
+            }
+
+            public Object parse(String formattedValue) throws Exception {
+                return Double.parseDouble(formattedValue);
+            }
+
+        });
adds formatter for Double-typed property that extends + * standard "1.0" notation with more zeroes. + *

+ * + * @param T + * type of the underlying property (a PropertyFormatter is always a + * Property<String>) + * + * @deprecated As of 7.0, replaced by {@link Converter} + * @author Vaadin Ltd. + * @since 5.3.0 + */ +@SuppressWarnings("serial") +@Deprecated +public abstract class PropertyFormatter extends AbstractProperty + implements Property.Viewer, Property.ValueChangeListener, + Property.ReadOnlyStatusChangeListener { + + /** Datasource that stores the actual value. */ + Property dataSource; + + /** + * Construct a new {@code PropertyFormatter} that is not connected to any + * data source. Call {@link #setPropertyDataSource(Property)} later on to + * attach it to a property. + * + */ + protected PropertyFormatter() { + } + + /** + * Construct a new formatter that is connected to given data source. Calls + * {@link #format(Object)} which can be a problem if the formatter has not + * yet been initialized. + * + * @param propertyDataSource + * to connect this property to. + */ + public PropertyFormatter(Property propertyDataSource) { + + setPropertyDataSource(propertyDataSource); + } + + /** + * Gets the current data source of the formatter, if any. + * + * @return the current data source as a Property, or null if + * none defined. + */ + @Override + public Property getPropertyDataSource() { + return dataSource; + } + + /** + * Sets the specified Property as the data source for the formatter. + * + * + *

+ * Remember that new data sources getValue() must return objects that are + * compatible with parse() and format() methods. + *

+ * + * @param newDataSource + * the new data source Property. + */ + @Override + public void setPropertyDataSource(Property newDataSource) { + + boolean readOnly = false; + String prevValue = null; + + if (dataSource != null) { + if (dataSource instanceof Property.ValueChangeNotifier) { + ((Property.ValueChangeNotifier) dataSource) + .removeListener(this); + } + if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { + ((Property.ReadOnlyStatusChangeNotifier) dataSource) + .removeListener(this); + } + readOnly = isReadOnly(); + prevValue = getValue(); + } + + dataSource = newDataSource; + + if (dataSource != null) { + if (dataSource instanceof Property.ValueChangeNotifier) { + ((Property.ValueChangeNotifier) dataSource).addListener(this); + } + if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { + ((Property.ReadOnlyStatusChangeNotifier) dataSource) + .addListener(this); + } + } + + if (isReadOnly() != readOnly) { + fireReadOnlyStatusChange(); + } + String newVal = getValue(); + if ((prevValue == null && newVal != null) + || (prevValue != null && !prevValue.equals(newVal))) { + fireValueChange(); + } + } + + /* Documented in the interface */ + @Override + public Class getType() { + return String.class; + } + + /** + * Get the formatted value. + * + * @return If the datasource returns null, this is null. Otherwise this is + * String given by format(). + */ + @Override + public String getValue() { + T value = dataSource == null ? null : dataSource.getValue(); + if (value == null) { + return null; + } + return format(value); + } + + /** Reflects the read-only status of the datasource. */ + @Override + public boolean isReadOnly() { + return dataSource == null ? false : dataSource.isReadOnly(); + } + + /** + * This method must be implemented to format the values received from + * DataSource. + * + * @param value + * Value object got from the datasource. This is guaranteed to be + * non-null and of the type compatible with getType() of the + * datasource. + * @return + */ + abstract public String format(T value); + + /** + * Parse string and convert it to format compatible with datasource. + * + * The method is required to assure that parse(format(x)) equals x. + * + * @param formattedValue + * This is guaranteed to be non-null string. + * @return Non-null value compatible with datasource. + * @throws Exception + * Any type of exception can be thrown to indicate that the + * conversion was not succesful. + */ + abstract public T parse(String formattedValue) throws Exception; + + /** + * Sets the Property's read-only mode to the specified status. + * + * @param newStatus + * the new read-only status of the Property. + */ + @Override + public void setReadOnly(boolean newStatus) { + if (dataSource != null) { + dataSource.setReadOnly(newStatus); + } + } + + @Override + public void setValue(String newValue) throws ReadOnlyException { + if (dataSource == null) { + return; + } + if (newValue == null) { + if (dataSource.getValue() != null) { + dataSource.setValue(null); + fireValueChange(); + } + } else { + try { + dataSource.setValue(parse(newValue.toString())); + if (!newValue.equals(getValue())) { + fireValueChange(); + } + } catch (Exception e) { + throw new IllegalArgumentException("Could not parse value", e); + } + } + } + + /** + * Listens for changes in the datasource. + * + * This should not be called directly. + */ + @Override + public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { + fireValueChange(); + } + + /** + * Listens for changes in the datasource. + * + * This should not be called directly. + */ + @Override + public void readOnlyStatusChange( + com.vaadin.v7.data.Property.ReadOnlyStatusChangeEvent event) { + fireReadOnlyStatusChange(); + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java new file mode 100644 index 0000000000..ce5bed8968 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java @@ -0,0 +1,157 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; + +/** + * Property implementation for wrapping a text file. + * + * Supports reading and writing of a File from/to String. + * + * {@link ValueChangeListener}s are supported, but only fire when + * setValue(Object) is explicitly called. {@link ReadOnlyStatusChangeListener}s + * are supported but only fire when setReadOnly(boolean) is explicitly called. + * + */ +@SuppressWarnings("serial") +public class TextFileProperty extends AbstractProperty { + + private File file; + private Charset charset = null; + + /** + * Wrap given file with property interface. + * + * Setting the file to null works, but getValue() will return null. + * + * @param file + * File to be wrapped. + */ + public TextFileProperty(File file) { + this.file = file; + } + + /** + * Wrap the given file with the property interface and specify character + * set. + * + * Setting the file to null works, but getValue() will return null. + * + * @param file + * File to be wrapped. + * @param charset + * Charset to be used for reading and writing the file. + */ + public TextFileProperty(File file, Charset charset) { + this.file = file; + this.charset = charset; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#getType() + */ + @Override + public Class getType() { + return String.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#getValue() + */ + @Override + public String getValue() { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + InputStreamReader isr = charset == null ? new InputStreamReader(fis) + : new InputStreamReader(fis, charset); + BufferedReader r = new BufferedReader(isr); + StringBuilder b = new StringBuilder(); + char buf[] = new char[8 * 1024]; + int len; + while ((len = r.read(buf)) != -1) { + b.append(buf, 0, len); + } + r.close(); + isr.close(); + fis.close(); + return b.toString(); + } catch (FileNotFoundException e) { + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#isReadOnly() + */ + @Override + public boolean isReadOnly() { + return file == null || super.isReadOnly() || !file.canWrite(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#setValue(java.lang.Object) + */ + @Override + public void setValue(String newValue) throws ReadOnlyException { + if (isReadOnly()) { + throw new ReadOnlyException(); + } + if (file == null) { + return; + } + + try { + FileOutputStream fos = new FileOutputStream(file); + OutputStreamWriter osw = charset == null + ? new OutputStreamWriter(fos) + : new OutputStreamWriter(fos, charset); + BufferedWriter w = new BufferedWriter(osw); + w.append(newValue.toString()); + w.flush(); + w.close(); + osw.close(); + fos.close(); + fireValueChange(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java new file mode 100644 index 0000000000..21afa4bc92 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.Property.ValueChangeEvent; +import com.vaadin.v7.data.Property.ValueChangeNotifier; + +/** + * Wrapper class that helps implement two-phase commit for a non-transactional + * property. + * + * When accessing the property through the wrapper, getting and setting the + * property value take place immediately. However, the wrapper keeps track of + * the old value of the property so that it can be set for the property in case + * of a roll-back. This can result in the underlying property value changing + * multiple times (first based on modifications made by the application, then + * back upon roll-back). + * + * Value change events on the {@link TransactionalPropertyWrapper} are only + * fired at the end of a successful transaction, whereas listeners attached to + * the underlying property may receive multiple value change events. + * + * @see com.vaadin.v7.data.Property.Transactional + * + * @author Vaadin Ltd + * @since 7.0 + * + * @param + */ +public class TransactionalPropertyWrapper extends AbstractProperty + implements ValueChangeNotifier, Property.Transactional { + + private Property wrappedProperty; + private boolean inTransaction = false; + private boolean valueChangePending; + private T valueBeforeTransaction; + private final ValueChangeListener listener = new ValueChangeListener() { + + @Override + public void valueChange(ValueChangeEvent event) { + fireValueChange(); + } + }; + + public TransactionalPropertyWrapper(Property wrappedProperty) { + this.wrappedProperty = wrappedProperty; + if (wrappedProperty instanceof ValueChangeNotifier) { + ((ValueChangeNotifier) wrappedProperty) + .addValueChangeListener(listener); + } + } + + /** + * Removes the ValueChangeListener from wrapped Property that was added by + * TransactionalPropertyWrapper. + * + * @since 7.1.15 + */ + public void detachFromProperty() { + if (wrappedProperty instanceof ValueChangeNotifier) { + ((ValueChangeNotifier) wrappedProperty) + .removeValueChangeListener(listener); + } + } + + @Override + public Class getType() { + return wrappedProperty.getType(); + } + + @Override + public T getValue() { + return wrappedProperty.getValue(); + } + + @Override + public void setValue(T newValue) throws ReadOnlyException { + // Causes a value change to be sent to this listener which in turn fires + // a new value change event for this property + wrappedProperty.setValue(newValue); + } + + @Override + public void startTransaction() { + inTransaction = true; + valueBeforeTransaction = getValue(); + } + + @Override + public void commit() { + endTransaction(); + } + + @Override + public void rollback() { + try { + wrappedProperty.setValue(valueBeforeTransaction); + } finally { + valueChangePending = false; + endTransaction(); + } + } + + protected void endTransaction() { + inTransaction = false; + valueBeforeTransaction = null; + if (valueChangePending) { + fireValueChange(); + } + } + + @Override + protected void fireValueChange() { + if (inTransaction) { + valueChangePending = true; + } else { + super.fireValueChange(); + } + } + + public Property getWrappedProperty() { + return wrappedProperty; + } + + @Override + public boolean isReadOnly() { + return wrappedProperty.isReadOnly(); + } + + @Override + public void setReadOnly(boolean newStatus) { + boolean oldStatus = isReadOnly(); + wrappedProperty.setReadOnly(newStatus); + if (oldStatus != isReadOnly()) { + fireReadOnlyStatusChange(); + } + } + +} diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java b/compatibility-server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java new file mode 100644 index 0000000000..71c562d425 --- /dev/null +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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 com.vaadin.v7.data.util; + +import java.io.Serializable; + +import com.vaadin.v7.data.Property; + +/** + * Property descriptor that can create a property instance for a bean. + * + * Used by {@link BeanItem} and {@link AbstractBeanContainer} to keep track of + * the set of properties of items. + * + * @param + * bean type + * + * @since 6.6 + */ +public interface VaadinPropertyDescriptor extends Serializable { + /** + * Returns the name of the property. + * + * @return + */ + public String getName(); + + /** + * Returns the type of the property. + * + * @return Class + */ + public Class getPropertyType(); + + /** + * Creates a new {@link Property} instance for this property for a bean. + * + * @param bean + * @return + */ + public Property createProperty(BT bean); +} diff --git a/compatibility-server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java b/compatibility-server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java new file mode 100644 index 0000000000..854f3666ac --- /dev/null +++ b/compatibility-server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java @@ -0,0 +1,30 @@ +package com.vaadin.tests.server; + +import org.junit.Test; + +import com.vaadin.tests.server.component.AbstractListenerMethodsTestBase; +import com.vaadin.v7.data.Property.ReadOnlyStatusChangeEvent; +import com.vaadin.v7.data.Property.ReadOnlyStatusChangeListener; +import com.vaadin.v7.data.Property.ValueChangeEvent; +import com.vaadin.v7.data.Property.ValueChangeListener; +import com.vaadin.v7.data.util.AbstractProperty; +import com.vaadin.v7.data.util.ObjectProperty; + +public class AbstractPropertyListenersTest + extends AbstractListenerMethodsTestBase { + + @Test + public void testValueChangeListenerAddGetRemove() throws Exception { + testListenerAddGetRemove(AbstractProperty.class, ValueChangeEvent.class, + ValueChangeListener.class, new ObjectProperty("")); + } + + @Test + public void testReadOnlyStatusChangeListenerAddGetRemove() + throws Exception { + testListenerAddGetRemove(AbstractProperty.class, + ReadOnlyStatusChangeEvent.class, + ReadOnlyStatusChangeListener.class, + new ObjectProperty("")); + } +} diff --git a/compatibility-server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java b/compatibility-server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java new file mode 100644 index 0000000000..775018642a --- /dev/null +++ b/compatibility-server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java @@ -0,0 +1,75 @@ +package com.vaadin.tests.server; + +import static org.junit.Assert.assertTrue; + +import java.util.Date; + +import org.junit.Test; + +import com.vaadin.v7.data.util.ObjectProperty; +import com.vaadin.v7.data.util.PropertyFormatter; + +@SuppressWarnings("unchecked") +public class PropertyFormatterTest { + + class TestFormatter extends PropertyFormatter { + + @Override + public String format(Object value) { + boolean isCorrectType = getExpectedClass() + .isAssignableFrom(value.getClass()); + assertTrue(isCorrectType); + return "FOO"; + } + + @Override + public Object parse(String formattedValue) throws Exception { + return getExpectedClass().newInstance(); + } + } + + @SuppressWarnings("rawtypes") + private Class expectedClass; + + @SuppressWarnings("rawtypes") + private Class getExpectedClass() { + return expectedClass; + } + + /** + * The object passed to format should be same as property's type. + * + * @throws IllegalAccessException + * @throws InstantiationException + */ + @Test + @SuppressWarnings({ "rawtypes" }) + public void testCorrectTypeForFormat() + throws InstantiationException, IllegalAccessException { + Class[] testedTypes = new Class[] { Integer.class, Boolean.class, + Double.class, String.class, Date.class }; + Object[] testValues = new Object[] { new Integer(3), Boolean.FALSE, + new Double(3.3), "bar", new Date() }; + + int i = 0; + for (Class class1 : testedTypes) { + expectedClass = class1; + + TestFormatter formatter = new TestFormatter(); + + // Should just return null, without formatting + Object value = formatter.getValue(); + + // test with property which value is null + formatter.setPropertyDataSource( + new ObjectProperty(null, expectedClass)); + formatter.getValue(); // calls format + + // test with a value + formatter.setPropertyDataSource( + new ObjectProperty(testValues[i++], expectedClass)); + formatter.getValue(); // calls format + } + + } +} diff --git a/server/src/main/java/com/vaadin/v7/data/Buffered.java b/server/src/main/java/com/vaadin/v7/data/Buffered.java deleted file mode 100644 index 025a43fbba..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/Buffered.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data; - -import java.io.Serializable; - -import com.vaadin.server.AbstractErrorMessage; -import com.vaadin.server.ErrorMessage; -import com.vaadin.server.ErrorMessage.ErrorLevel; -import com.vaadin.server.ErrorMessageProducer; -import com.vaadin.server.UserError; -import com.vaadin.v7.data.Validator.InvalidValueException; - -/** - *

- * Defines the interface to commit and discard changes to an object, supporting - * buffering. - * - *

- * In buffered mode the initial value is read from the data source and - * then buffered. Any subsequential writes or reads will be done on the buffered - * value. Calling {@link #commit()} will write the buffered value to the data - * source while calling {@link #discard()} while discard the buffered value and - * re-read the value from the data source. - * - *

- * In non-buffered mode the value is always read directly from the data - * source. Any write is done directly to the data source with no buffering in - * between. Reads are also done directly from the data source. Calling - * {@link #commit()} or {@link #discard()} in this mode is efficiently a no-op. - * - * @author Vaadin Ltd. - * @since 3.0 - */ -public interface Buffered extends Serializable { - - /** - * Updates all changes since the previous commit to the data source. The - * value stored in the object will always be updated into the data source - * when commit is called. - * - * @throws SourceException - * if the operation fails because of an exception is thrown by - * the data source. The cause is included in the exception. - * @throws InvalidValueException - * if the operation fails because validation is enabled and the - * values do not validate - */ - public void commit() throws SourceException, InvalidValueException; - - /** - * Discards all changes since last commit. The object updates its value from - * the data source. - * - * @throws SourceException - * if the operation fails because of an exception is thrown by - * the data source. The cause is included in the exception. - */ - public void discard() throws SourceException; - - /** - * Sets the buffered mode to the specified status. - *

- * When in buffered mode, an internal buffer will be used to store changes - * until {@link #commit()} is called. Calling {@link #discard()} will revert - * the internal buffer to the value of the data source. - *

- * When in non-buffered mode both read and write operations will be done - * directly on the data source. In this mode the {@link #commit()} and - * {@link #discard()} methods serve no purpose. - * - * @param buffered - * true if buffered mode should be turned on, false otherwise - * @since 7.0 - */ - public void setBuffered(boolean buffered); - - /** - * Checks the buffered mode - * - * @return true if buffered mode is on, false otherwise - * @since 7.0 - */ - public boolean isBuffered(); - - /** - * Tests if the value stored in the object has been modified since it was - * last updated from the data source. - * - * @return true if the value in the object has been modified - * since the last data source update, false if not. - */ - public boolean isModified(); - - /** - * An exception that signals that one or more exceptions occurred while a - * buffered object tried to access its data source or if there is a problem - * in processing a data source. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - @SuppressWarnings("serial") - public class SourceException extends RuntimeException - implements Serializable, ErrorMessageProducer { - - /** Source class implementing the buffered interface */ - private final Buffered source; - - /** Original cause of the source exception */ - private Throwable[] causes = {}; - - /** - * Creates a source exception that does not include a cause. - * - * @param source - * the source object implementing the Buffered interface. - */ - public SourceException(Buffered source) { - this.source = source; - } - - /** - * Creates a source exception from multiple causes. - * - * @param source - * the source object implementing the Buffered interface. - * @param causes - * the original causes for this exception. - */ - public SourceException(Buffered source, Throwable... causes) { - this.source = source; - this.causes = causes; - } - - /** - * Gets the cause of the exception. - * - * @return The (first) cause for the exception, null if no cause. - */ - @Override - public final Throwable getCause() { - if (causes.length == 0) { - return null; - } - return causes[0]; - } - - /** - * Gets all the causes for this exception. - * - * @return throwables that caused this exception - */ - public final Throwable[] getCauses() { - return causes; - } - - /** - * Gets a source of the exception. - * - * @return the Buffered object which generated this exception. - */ - public Buffered getSource() { - return source; - } - - @Override - public ErrorMessage getErrorMessage() { - // no message, only the causes to be painted - UserError error = new UserError(null); - // in practice, this was always ERROR in Vaadin 6 unless tweaked in - // custom exceptions implementing ErrorMessage - error.setErrorLevel(ErrorLevel.ERROR); - // causes - for (Throwable nestedException : getCauses()) { - error.addCause(AbstractErrorMessage - .getErrorMessageForException(nestedException)); - } - return error; - } - - } -} diff --git a/server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java b/server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java deleted file mode 100644 index ea0b3c0ebd..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/BufferedValidatable.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data; - -import java.io.Serializable; - -/** - *

- * This interface defines the combination of Validatable and - * Buffered interfaces. The combination of the interfaces defines - * if the invalid data is committed to datasource. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ -public interface BufferedValidatable - extends Buffered, Validatable, Serializable { - - /** - * Tests if the invalid data is committed to datasource. The default is - * false. - */ - public boolean isInvalidCommitted(); - - /** - * Sets if the invalid data should be committed to datasource. The default - * is false. - */ - public void setInvalidCommitted(boolean isCommitted); -} diff --git a/server/src/main/java/com/vaadin/v7/data/Property.java b/server/src/main/java/com/vaadin/v7/data/Property.java deleted file mode 100644 index 21129a64f9..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/Property.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data; - -import java.io.Serializable; - -/** - *

- * The Property is a simple data object that contains one typed - * value. This interface contains methods to inspect and modify the stored value - * and its type, and the object's read-only state. - *

- * - *

- * The Property also defines the events - * ReadOnlyStatusChangeEvent and ValueChangeEvent, and - * the associated listener and notifier interfaces. - *

- * - *

- * The Property.Viewer interface should be used to attach the - * Property to an external data source. This way the value in the data source - * can be inspected using the Property interface. - *

- * - *

- * The Property.editor interface should be implemented if the value - * needs to be changed through the implementing class. - *

- * - * @param T - * type of values of the property - * - * @author Vaadin Ltd - * @since 3.0 - */ -public interface Property extends Serializable { - - /** - * Gets the value stored in the Property. The returned object is compatible - * with the class returned by getType(). - * - * @return the value stored in the Property - */ - public T getValue(); - - /** - * Sets the value of the Property. - *

- * Implementing this functionality is optional. If the functionality is - * missing, one should declare the Property to be in read-only mode and - * throw Property.ReadOnlyException in this function. - *

- * - * Note : Since Vaadin 7.0, setting the value of a non-String property as a - * String is no longer supported. - * - * @param newValue - * New value of the Property. This should be assignable to the - * type returned by getType - * - * @throws Property.ReadOnlyException - * if the object is in read-only mode - */ - public void setValue(T newValue) throws Property.ReadOnlyException; - - /** - * Returns the type of the Property. The methods getValue and - * setValue must be compatible with this type: one must be able - * to safely cast the value returned from getValue to the given - * type and pass any variable assignable to this type as an argument to - * setValue. - * - * @return type of the Property - */ - public Class getType(); - - /** - * Tests if the Property is in read-only mode. In read-only mode calls to - * the method setValue will throw - * ReadOnlyException and will not modify the value of the - * Property. - * - * @return true if the Property is in read-only mode, - * false if it's not - */ - public boolean isReadOnly(); - - /** - * Sets the Property's read-only mode to the specified status. - * - * This functionality is optional, but all properties must implement the - * isReadOnly mode query correctly. - * - * @param newStatus - * new read-only status of the Property - */ - public void setReadOnly(boolean newStatus); - - /** - * A Property that is capable of handle a transaction that can end in commit - * or rollback. - * - * Note that this does not refer to e.g. database transactions but rather - * two-phase commit that allows resetting old field values (in e.g. a - * FieldGroup) if the commit of one of the properties fails after other - * properties have already been committed. - * - * @param - * The type of the property - * @author Vaadin Ltd - * @since 7.0 - */ - public interface Transactional extends Property { - - /** - * Starts a transaction. - * - *

- * If the value is set during a transaction the value must not replace - * the original value until {@link #commit()} is called. Still, - * {@link #getValue()} must return the current value set in the - * transaction. Calling {@link #rollback()} while in a transaction must - * rollback the value to what it was before the transaction started. - *

- *

- * {@link ValueChangeEvent}s must not be emitted for internal value - * changes during a transaction. If the value changes as a result of - * {@link #commit()}, a {@link ValueChangeEvent} should be emitted. - *

- */ - public void startTransaction(); - - /** - * Commits and ends the transaction that is in progress. - *

- * If the value is changed as a result of this operation, a - * {@link ValueChangeEvent} is emitted if such are supported. - *

- * This method has no effect if there is no transaction is in progress. - *

- * This method must never throw an exception. - */ - public void commit(); - - /** - * Aborts and rolls back the transaction that is in progress. - *

- * The value is reset to the value before the transaction started. No - * {@link ValueChangeEvent} is emitted as a result of this. - *

- * This method has no effect if there is no transaction is in progress. - *

- * This method must never throw an exception. - */ - public void rollback(); - } - - /** - * Exception object that signals that a requested Property - * modification failed because it's in read-only mode. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - @SuppressWarnings("serial") - public class ReadOnlyException extends RuntimeException { - - /** - * Constructs a new ReadOnlyException without a detail - * message. - */ - public ReadOnlyException() { - } - - /** - * Constructs a new ReadOnlyException with the specified - * detail message. - * - * @param msg - * the detail message - */ - public ReadOnlyException(String msg) { - super(msg); - } - } - - /** - * Interface implemented by the viewer classes capable of using a Property - * as a data source. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface Viewer extends Serializable { - - /** - * Sets the Property that serves as the data source of the viewer. - * - * @param newDataSource - * the new data source Property - */ - public void setPropertyDataSource(Property newDataSource); - - /** - * Gets the Property serving as the data source of the viewer. - * - * @return the Property serving as the viewers data source - */ - public Property getPropertyDataSource(); - } - - /** - * Interface implemented by the editor classes capable of editing the - * Property. - *

- * Implementing this interface means that the Property serving as the data - * source of the editor can be modified through the editor. It does not - * restrict the editor from editing the Property internally, though if the - * Property is in a read-only mode, attempts to modify it will result in the - * ReadOnlyException being thrown. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface Editor extends Property.Viewer, Serializable { - - } - - /* Value change event */ - - /** - * An Event object specifying the Property whose value has been - * changed. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface ValueChangeEvent extends Serializable { - - /** - * Retrieves the Property that has been modified. - * - * @return source Property of the event - */ - public Property getProperty(); - } - - /** - * The listener interface for receiving - * ValueChangeEvent objects. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface ValueChangeListener extends Serializable { - - /** - * Notifies this listener that the Property's value has changed. - * - * @param event - * value change event object - */ - public void valueChange(Property.ValueChangeEvent event); - } - - /** - * The interface for adding and removing ValueChangeEvent - * listeners. If a Property wishes to allow other objects to receive - * ValueChangeEvent generated by it, it must implement this - * interface. - *

- * Note : The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * addListener and removeListener methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface ValueChangeNotifier extends Serializable { - - /** - * Registers a new value change listener for this Property. - * - * @param listener - * the new Listener to be registered - */ - public void addValueChangeListener( - Property.ValueChangeListener listener); - - /** - * @deprecated As of 7.0, replaced by - * {@link #addValueChangeListener(ValueChangeListener)} - **/ - @Deprecated - public void addListener(Property.ValueChangeListener listener); - - /** - * Removes a previously registered value change listener. - * - * @param listener - * listener to be removed - */ - public void removeValueChangeListener( - Property.ValueChangeListener listener); - - /** - * @deprecated As of 7.0, replaced by - * {@link #removeValueChangeListener(ValueChangeListener)} - **/ - @Deprecated - public void removeListener(Property.ValueChangeListener listener); - } - - /* ReadOnly Status change event */ - - /** - * An Event object specifying the Property whose read-only - * status has been changed. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface ReadOnlyStatusChangeEvent extends Serializable { - - /** - * Property whose read-only state has changed. - * - * @return source Property of the event. - */ - public Property getProperty(); - } - - /** - * The listener interface for receiving - * ReadOnlyStatusChangeEvent objects. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface ReadOnlyStatusChangeListener extends Serializable { - - /** - * Notifies this listener that a Property's read-only status has - * changed. - * - * @param event - * Read-only status change event object - */ - public void readOnlyStatusChange( - Property.ReadOnlyStatusChangeEvent event); - } - - /** - * The interface for adding and removing - * ReadOnlyStatusChangeEvent listeners. If a Property wishes to - * allow other objects to receive ReadOnlyStatusChangeEvent - * generated by it, it must implement this interface. - *

- * Note : The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * addListener and removeListener methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ - public interface ReadOnlyStatusChangeNotifier extends Serializable { - - /** - * Registers a new read-only status change listener for this Property. - * - * @param listener - * the new Listener to be registered - */ - public void addReadOnlyStatusChangeListener( - Property.ReadOnlyStatusChangeListener listener); - - /** - * @deprecated As of 7.0, replaced by - * {@link #addReadOnlyStatusChangeListener(ReadOnlyStatusChangeListener)} - **/ - @Deprecated - public void addListener(Property.ReadOnlyStatusChangeListener listener); - - /** - * Removes a previously registered read-only status change listener. - * - * @param listener - * listener to be removed - */ - public void removeReadOnlyStatusChangeListener( - Property.ReadOnlyStatusChangeListener listener); - - /** - * @deprecated As of 7.0, replaced by - * {@link #removeReadOnlyStatusChangeListener(ReadOnlyStatusChangeListener)} - **/ - @Deprecated - public void removeListener( - Property.ReadOnlyStatusChangeListener listener); - } -} diff --git a/server/src/main/java/com/vaadin/v7/data/Validatable.java b/server/src/main/java/com/vaadin/v7/data/Validatable.java deleted file mode 100644 index 5c75d594ba..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/Validatable.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data; - -import java.io.Serializable; -import java.util.Collection; - -/** - *

- * Interface for validatable objects. Defines methods to verify if the object's - * value is valid or not, and to add, remove and list registered validators of - * the object. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - * @see com.vaadin.v7.data.Validator - */ -public interface Validatable extends Serializable { - - /** - *

- * Adds a new validator for this object. The validator's - * {@link Validator#validate(Object)} method is activated every time the - * object's value needs to be verified, that is, when the {@link #isValid()} - * method is called. This usually happens when the object's value changes. - *

- * - * @param validator - * the new validator - */ - void addValidator(Validator validator); - - /** - *

- * Removes a previously registered validator from the object. The specified - * validator is removed from the object and its validate method - * is no longer called in {@link #isValid()}. - *

- * - * @param validator - * the validator to remove - */ - void removeValidator(Validator validator); - - /** - * Removes all validators from this object, as if - * {@link #removeValidator(Validator) removeValidator} was called for each - * registered validator. - */ - void removeAllValidators(); - - /** - *

- * Returns a collection of all validators currently registered for the - * object. The collection may be immutable. Calling - * removeValidator for this Validatable while iterating over - * the collection may be unsafe (e.g. may throw - * ConcurrentModificationException.) - *

- * - * @return A collection of validators - */ - public Collection getValidators(); - - /** - *

- * Tests the current value of the object against all registered validators. - * The registered validators are iterated and for each the - * {@link Validator#validate(Object)} method is called. If any validator - * throws the {@link Validator.InvalidValueException} this method returns - * false. - *

- * - * @return true if the registered validators concur that the - * value is valid, false otherwise - */ - public boolean isValid(); - - /** - *

- * Checks the validity of the validatable. If the validatable is valid this - * method should do nothing, and if it's not valid, it should throw - * Validator.InvalidValueException - *

- * - * @throws Validator.InvalidValueException - * if the value is not valid - */ - public void validate() throws Validator.InvalidValueException; - - /** - *

- * Checks the validabtable object accept invalid values.The default value is - * true. - *

- * - */ - public boolean isInvalidAllowed(); - - /** - *

- * Should the validabtable object accept invalid values. Supporting this - * configuration possibility is optional. By default invalid values are - * allowed. - *

- * - * @param invalidValueAllowed - * - * @throws UnsupportedOperationException - * if the setInvalidAllowed is not supported. - */ - public void setInvalidAllowed(boolean invalidValueAllowed) - throws UnsupportedOperationException; - -} diff --git a/server/src/main/java/com/vaadin/v7/data/Validator.java b/server/src/main/java/com/vaadin/v7/data/Validator.java deleted file mode 100644 index a6ad0331ed..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/Validator.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data; - -import java.io.Serializable; - -import com.vaadin.server.AbstractErrorMessage; -import com.vaadin.server.AbstractErrorMessage.ContentMode; -import com.vaadin.server.ErrorMessage; -import com.vaadin.server.ErrorMessage.ErrorLevel; -import com.vaadin.server.ErrorMessageProducer; -import com.vaadin.server.UserError; -import com.vaadin.server.VaadinServlet; - -/** - * Interface that implements a method for validating if an {@link Object} is - * valid or not. - *

- * Implementors of this class can be added to any - * {@link com.vaadin.v7.data.Validatable Validatable} implementor to verify its - * value. - *

- *

- * {@link #validate(Object)} can be used to check if a value is valid. An - * {@link InvalidValueException} with an appropriate validation error message is - * thrown if the value is not valid. - *

- *

- * Validators must not have any side effects. - *

- *

- * Since Vaadin 7, the method isValid(Object) does not exist in the interface - - * {@link #validate(Object)} should be used instead, and the exception caught - * where applicable. Concrete classes implementing {@link Validator} can still - * internally implement and use isValid(Object) for convenience or to ease - * migration from earlier Vaadin versions. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ -public interface Validator extends Serializable { - - /** - * Checks the given value against this validator. If the value is valid the - * method does nothing. If the value is invalid, an - * {@link InvalidValueException} is thrown. - * - * @param value - * the value to check - * @throws Validator.InvalidValueException - * if the value is invalid - */ - public void validate(Object value) throws Validator.InvalidValueException; - - /** - * Exception that is thrown by a {@link Validator} when a value is invalid. - * - *

- * The default implementation of InvalidValueException does not support HTML - * in error messages. To enable HTML support, override - * {@link #getHtmlMessage()} and use the subclass in validators. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ - @SuppressWarnings("serial") - public class InvalidValueException extends RuntimeException - implements ErrorMessageProducer { - - /** - * Array of one or more validation errors that are causing this - * validation error. - */ - private InvalidValueException[] causes = null; - - /** - * Constructs a new {@code InvalidValueException} with the specified - * message. - * - * @param message - * The detail message of the problem. - */ - public InvalidValueException(String message) { - this(message, new InvalidValueException[] {}); - } - - /** - * Constructs a new {@code InvalidValueException} with a set of causing - * validation exceptions. The causing validation exceptions are included - * when the exception is painted to the client. - * - * @param message - * The detail message of the problem. - * @param causes - * One or more {@code InvalidValueException}s that caused - * this exception. - */ - public InvalidValueException(String message, - InvalidValueException... causes) { - super(message); - if (causes == null) { - throw new NullPointerException( - "Possible causes array must not be null"); - } - - this.causes = causes; - } - - /** - * Check if the error message should be hidden. - * - * An empty (null or "") message is invisible unless it contains nested - * exceptions that are visible. - * - * @return true if the error message should be hidden, false otherwise - */ - public boolean isInvisible() { - String msg = getMessage(); - if (msg != null && msg.length() > 0) { - return false; - } - if (causes != null) { - for (int i = 0; i < causes.length; i++) { - if (!causes[i].isInvisible()) { - return false; - } - } - } - return true; - } - - /** - * Returns the message of the error in HTML. - * - * Note that this API may change in future versions. - */ - public String getHtmlMessage() { - return VaadinServlet.safeEscapeForHtml(getLocalizedMessage()); - } - - /** - * Returns the {@code InvalidValueExceptions} that caused this - * exception. - * - * @return An array containing the {@code InvalidValueExceptions} that - * caused this exception. Returns an empty array if this - * exception was not caused by other exceptions. - */ - public InvalidValueException[] getCauses() { - return causes; - } - - @Override - public ErrorMessage getErrorMessage() { - UserError error = new UserError(getHtmlMessage(), ContentMode.HTML, - ErrorLevel.ERROR); - for (Validator.InvalidValueException nestedException : getCauses()) { - error.addCause(AbstractErrorMessage - .getErrorMessageForException(nestedException)); - } - return error; - } - - } - - /** - * A specific type of {@link InvalidValueException} that indicates that - * validation failed because the value was empty. What empty means is up to - * the thrower. - * - * @author Vaadin Ltd. - * @since 5.3.0 - */ - @SuppressWarnings("serial") - public class EmptyValueException extends Validator.InvalidValueException { - - public EmptyValueException(String message) { - super(message); - } - - } -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java b/server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java deleted file mode 100644 index 33d22777ad..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/AbstractProperty.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.logging.Logger; - -import com.vaadin.v7.data.Property; - -/** - * Abstract base class for {@link Property} implementations. - * - * Handles listener management for {@link ValueChangeListener}s and - * {@link ReadOnlyStatusChangeListener}s. - * - * @since 6.6 - */ -public abstract class AbstractProperty implements Property, - Property.ValueChangeNotifier, Property.ReadOnlyStatusChangeNotifier { - - /** - * List of listeners who are interested in the read-only status changes of - * the Property - */ - private LinkedList readOnlyStatusChangeListeners = null; - - /** - * List of listeners who are interested in the value changes of the Property - */ - private LinkedList valueChangeListeners = null; - - /** - * Is the Property read-only? - */ - private boolean readOnly; - - /** - * {@inheritDoc} - * - * Override for additional restrictions on what is considered a read-only - * property. - */ - @Override - public boolean isReadOnly() { - return readOnly; - } - - @Override - public void setReadOnly(boolean newStatus) { - boolean oldStatus = isReadOnly(); - readOnly = newStatus; - if (oldStatus != isReadOnly()) { - fireReadOnlyStatusChange(); - } - } - - /* Events */ - - /** - * An Event object specifying the Property whose read-only - * status has been changed. - */ - protected static class ReadOnlyStatusChangeEvent - extends java.util.EventObject - implements Property.ReadOnlyStatusChangeEvent { - - /** - * Constructs a new read-only status change event for this object. - * - * @param source - * source object of the event. - */ - protected ReadOnlyStatusChangeEvent(Property source) { - super(source); - } - - /** - * Gets the Property whose read-only state has changed. - * - * @return source Property of the event. - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - - } - - /** - * Registers a new read-only status change listener for this Property. - * - * @param listener - * the new Listener to be registered. - */ - @Override - public void addReadOnlyStatusChangeListener( - Property.ReadOnlyStatusChangeListener listener) { - if (readOnlyStatusChangeListeners == null) { - readOnlyStatusChangeListeners = new LinkedList(); - } - readOnlyStatusChangeListeners.add(listener); - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #addReadOnlyStatusChangeListener(com.vaadin.v7.data.Property.ReadOnlyStatusChangeListener)} - **/ - @Override - @Deprecated - public void addListener(Property.ReadOnlyStatusChangeListener listener) { - addReadOnlyStatusChangeListener(listener); - } - - /** - * Removes a previously registered read-only status change listener. - * - * @param listener - * the listener to be removed. - */ - @Override - public void removeReadOnlyStatusChangeListener( - Property.ReadOnlyStatusChangeListener listener) { - if (readOnlyStatusChangeListeners != null) { - readOnlyStatusChangeListeners.remove(listener); - } - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #removeReadOnlyStatusChangeListener(com.vaadin.v7.data.Property.ReadOnlyStatusChangeListener)} - **/ - @Override - @Deprecated - public void removeListener(Property.ReadOnlyStatusChangeListener listener) { - removeReadOnlyStatusChangeListener(listener); - } - - /** - * Sends a read only status change event to all registered listeners. - */ - protected void fireReadOnlyStatusChange() { - if (readOnlyStatusChangeListeners != null) { - final Object[] l = readOnlyStatusChangeListeners.toArray(); - final Property.ReadOnlyStatusChangeEvent event = new ReadOnlyStatusChangeEvent( - this); - for (int i = 0; i < l.length; i++) { - ((Property.ReadOnlyStatusChangeListener) l[i]) - .readOnlyStatusChange(event); - } - } - } - - /** - * An Event object specifying the Property whose value has been - * changed. - */ - private static class ValueChangeEvent extends java.util.EventObject - implements Property.ValueChangeEvent { - - /** - * Constructs a new value change event for this object. - * - * @param source - * source object of the event. - */ - protected ValueChangeEvent(Property source) { - super(source); - } - - /** - * Gets the Property whose value has changed. - * - * @return source Property of the event. - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - - } - - @Override - public void addValueChangeListener(ValueChangeListener listener) { - if (valueChangeListeners == null) { - valueChangeListeners = new LinkedList(); - } - valueChangeListeners.add(listener); - - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #addValueChangeListener(com.vaadin.v7.data.Property.ValueChangeListener)} - **/ - @Override - @Deprecated - public void addListener(ValueChangeListener listener) { - addValueChangeListener(listener); - } - - @Override - public void removeValueChangeListener(ValueChangeListener listener) { - if (valueChangeListeners != null) { - valueChangeListeners.remove(listener); - } - - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #removeValueChangeListener(com.vaadin.v7.data.Property.ValueChangeListener)} - **/ - @Override - @Deprecated - public void removeListener(ValueChangeListener listener) { - removeValueChangeListener(listener); - } - - /** - * Sends a value change event to all registered listeners. - */ - protected void fireValueChange() { - if (valueChangeListeners != null) { - final Object[] l = valueChangeListeners.toArray(); - final Property.ValueChangeEvent event = new ValueChangeEvent(this); - for (int i = 0; i < l.length; i++) { - ((Property.ValueChangeListener) l[i]).valueChange(event); - } - } - } - - public Collection getListeners(Class eventType) { - if (Property.ValueChangeEvent.class.isAssignableFrom(eventType)) { - if (valueChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections.unmodifiableCollection(valueChangeListeners); - } - } else if (Property.ReadOnlyStatusChangeEvent.class - .isAssignableFrom(eventType)) { - if (readOnlyStatusChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(readOnlyStatusChangeListeners); - } - } - - return Collections.EMPTY_LIST; - } - - private static Logger getLogger() { - return Logger.getLogger(AbstractProperty.class.getName()); - } -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/ListSet.java b/server/src/main/java/com/vaadin/v7/data/util/ListSet.java deleted file mode 100644 index 2fd182238d..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/ListSet.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; - -/** - * ListSet is an internal Vaadin class which implements a combination of a List - * and a Set. The main purpose of this class is to provide a list with a fast - * {@link #contains(Object)} method. Each inserted object must by unique (as - * specified by {@link #equals(Object)}). The {@link #set(int, Object)} method - * allows duplicates because of the way {@link Collections#sort(java.util.List)} - * works. - * - * This class is subject to change and should not be used outside Vaadin core. - */ -public class ListSet extends ArrayList { - private HashSet itemSet = null; - - /** - * Contains a map from an element to the number of duplicates it has. Used - * to temporarily allow duplicates in the list. - */ - private HashMap duplicates = new HashMap(); - - public ListSet() { - super(); - itemSet = new HashSet(); - } - - public ListSet(Collection c) { - super(c); - itemSet = new HashSet(c.size()); - itemSet.addAll(c); - } - - public ListSet(int initialCapacity) { - super(initialCapacity); - itemSet = new HashSet(initialCapacity); - } - - // Delegate contains operations to the set - @Override - public boolean contains(Object o) { - return itemSet.contains(o); - } - - @Override - public boolean containsAll(Collection c) { - return itemSet.containsAll(c); - } - - // Methods for updating the set when the list is updated. - @Override - public boolean add(E e) { - if (contains(e)) { - // Duplicates are not allowed - return false; - } - - if (super.add(e)) { - itemSet.add(e); - return true; - } else { - return false; - } - } - - /** - * Works as java.util.ArrayList#add(int, java.lang.Object) but returns - * immediately if the element is already in the ListSet. - */ - @Override - public void add(int index, E element) { - if (contains(element)) { - // Duplicates are not allowed - return; - } - - super.add(index, element); - itemSet.add(element); - } - - @Override - public boolean addAll(Collection c) { - boolean modified = false; - Iterator i = c.iterator(); - while (i.hasNext()) { - E e = i.next(); - if (contains(e)) { - continue; - } - - if (add(e)) { - itemSet.add(e); - modified = true; - } - } - return modified; - } - - @Override - public boolean addAll(int index, Collection c) { - ensureCapacity(size() + c.size()); - - boolean modified = false; - Iterator i = c.iterator(); - while (i.hasNext()) { - E e = i.next(); - if (contains(e)) { - continue; - } - - add(index++, e); - itemSet.add(e); - modified = true; - } - - return modified; - } - - @Override - public void clear() { - super.clear(); - itemSet.clear(); - } - - @Override - public int indexOf(Object o) { - if (!contains(o)) { - return -1; - } - - return super.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - if (!contains(o)) { - return -1; - } - - return super.lastIndexOf(o); - } - - @Override - public E remove(int index) { - E e = super.remove(index); - - if (e != null) { - itemSet.remove(e); - } - - return e; - } - - @Override - public boolean remove(Object o) { - if (super.remove(o)) { - itemSet.remove(o); - return true; - } else { - return false; - } - } - - @Override - protected void removeRange(int fromIndex, int toIndex) { - HashSet toRemove = new HashSet(); - for (int idx = fromIndex; idx < toIndex; idx++) { - toRemove.add(get(idx)); - } - super.removeRange(fromIndex, toIndex); - itemSet.removeAll(toRemove); - } - - @Override - public E set(int index, E element) { - if (contains(element)) { - // Element already exist in the list - if (get(index) == element) { - // At the same position, nothing to be done - return element; - } else { - // Adding at another position. We assume this is a sort - // operation and temporarily allow it. - - // We could just remove (null) the old element and keep the list - // unique. This would require finding the index of the old - // element (indexOf(element)) which is not a fast operation in a - // list. So we instead allow duplicates temporarily. - addDuplicate(element); - } - } - - E old = super.set(index, element); - removeFromSet(old); - itemSet.add(element); - - return old; - } - - /** - * Removes "e" from the set if it no longer exists in the list. - * - * @param e - */ - private void removeFromSet(E e) { - Integer dupl = duplicates.get(e); - if (dupl != null) { - // A duplicate was present so we only decrement the duplicate count - // and continue - if (dupl == 1) { - // This is what always should happen. A sort sets the items one - // by one, temporarily breaking the uniqueness requirement. - duplicates.remove(e); - } else { - duplicates.put(e, dupl - 1); - } - } else { - // The "old" value is no longer in the list. - itemSet.remove(e); - } - - } - - /** - * Marks the "element" can be found more than once from the list. Allowed in - * {@link #set(int, Object)} to make sorting work. - * - * @param element - */ - private void addDuplicate(E element) { - Integer nr = duplicates.get(element); - if (nr == null) { - nr = 1; - } else { - nr++; - } - - /* - * Store the number of duplicates of this element so we know later on if - * we should remove an element from the set or if it was a duplicate (in - * removeFromSet) - */ - duplicates.put(element, nr); - - } - - @SuppressWarnings("unchecked") - @Override - public Object clone() { - ListSet v = (ListSet) super.clone(); - v.itemSet = new HashSet(itemSet); - return v; - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java b/server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java deleted file mode 100644 index 86fb0ae40d..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/MethodProperty.java +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import static com.vaadin.util.ReflectTools.convertPrimitiveType; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.shared.util.SharedUtil; -import com.vaadin.util.SerializerHelper; -import com.vaadin.v7.data.Property; - -/** - *

- * Proxy class for creating Properties from pairs of getter and setter methods - * of a Bean property. An instance of this class can be thought as having been - * attached to a field of an object. Accessing the object through the Property - * interface directly manipulates the underlying field. - *

- * - *

- * It's assumed that the return value returned by the getter method is - * assignable to the type of the property, and the setter method parameter is - * assignable to that value. - *

- * - *

- * A valid getter method must always be available, but instance of this class - * can be constructed with a null setter method in which case the - * resulting MethodProperty is read-only. - *

- * - *

- * MethodProperty implements Property.ValueChangeNotifier, but does not - * automatically know whether or not the getter method will actually return a - * new value - value change listeners are always notified when setValue is - * called, without verifying what the getter returns. - *

- * - * @author Vaadin Ltd. - * @since 3.0 - */ -@SuppressWarnings("serial") -public class MethodProperty extends AbstractProperty { - - /** - * The object that includes the property the MethodProperty is bound to. - */ - private transient Object instance; - - /** - * Argument arrays for the getter and setter methods. - */ - private transient Object[] setArgs, getArgs; - - /** - * The getter and setter methods. - */ - private transient Method setMethod, getMethod; - - /** - * Index of the new value in the argument list for the setter method. If the - * setter method requires several parameters, this index tells which one is - * the actual value to change. - */ - private int setArgumentIndex; - - /** - * Type of the property. - */ - private transient Class type; - - private static final Object[] DEFAULT_GET_ARGS = new Object[0]; - - private static final Object[] DEFAULT_SET_ARGS = new Object[1]; - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) - throws IOException { - out.defaultWriteObject(); - SerializerHelper.writeClass(out, type); - out.writeObject(instance); - out.writeObject(setArgs); - out.writeObject(getArgs); - if (setMethod != null) { - out.writeObject(setMethod.getName()); - SerializerHelper.writeClassArray(out, - setMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - } - if (getMethod != null) { - out.writeObject(getMethod.getName()); - SerializerHelper.writeClassArray(out, - getMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - } - } - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - try { - @SuppressWarnings("unchecked") - // business assumption; type parameters not checked at runtime - Class class1 = (Class) SerializerHelper.readClass(in); - type = class1; - instance = in.readObject(); - Object[] setArgs = (Object[]) in.readObject(); - Object[] getArgs = (Object[]) in.readObject(); - setArguments(getArgs, setArgs, setArgumentIndex); - String name = (String) in.readObject(); - Class[] paramTypes = SerializerHelper.readClassArray(in); - if (instance != null && name != null) { - setMethod = instance.getClass().getMethod(name, paramTypes); - } else { - setMethod = null; - } - - name = (String) in.readObject(); - paramTypes = SerializerHelper.readClassArray(in); - if (instance != null && name != null) { - getMethod = instance.getClass().getMethod(name, paramTypes); - } else { - getMethod = null; - } - } catch (SecurityException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } catch (NoSuchMethodException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } - } - - /** - *

- * Creates a new instance of MethodProperty from a named bean - * property. This constructor takes an object and the name of a bean - * property and initializes itself with the accessor methods for the - * property. - *

- *

- * The getter method of a MethodProperty instantiated with this - * constructor will be called with no arguments, and the setter method with - * only the new value as the sole argument. - *

- * - *

- * If the setter method is unavailable, the resulting - * MethodProperty will be read-only, otherwise it will be - * read-write. - *

- * - *

- * Method names are constructed from the bean property by adding - * get/is/are/set prefix and capitalising the first character in the name of - * the given bean property. - *

- * - * @param instance - * the object that includes the property. - * @param beanPropertyName - * the name of the property to bind to. - */ - @SuppressWarnings("unchecked") - public MethodProperty(Object instance, String beanPropertyName) { - - final Class beanClass = instance.getClass(); - - // Assure that the first letter is upper cased (it is a common - // mistake to write firstName, not FirstName). - beanPropertyName = SharedUtil.capitalize(beanPropertyName); - - // Find the get method - getMethod = null; - try { - getMethod = initGetterMethod(beanPropertyName, beanClass); - } catch (final java.lang.NoSuchMethodException ignored) { - throw new MethodException(this, - "Bean property " + beanPropertyName + " can not be found"); - } - - // In case the get method is found, resolve the type - Class returnType = getMethod.getReturnType(); - - // Finds the set method - setMethod = null; - try { - setMethod = beanClass.getMethod("set" + beanPropertyName, - new Class[] { returnType }); - } catch (final java.lang.NoSuchMethodException skipped) { - } - - // Gets the return type from get method - if (returnType.isPrimitive()) { - type = (Class) convertPrimitiveType(returnType); - if (type.isPrimitive()) { - throw new MethodException(this, - "Bean property " + beanPropertyName - + " getter return type must not be void"); - } - } else { - type = (Class) returnType; - } - - setArguments(DEFAULT_GET_ARGS, DEFAULT_SET_ARGS, 0); - this.instance = instance; - } - - /** - *

- * Creates a new instance of MethodProperty from named getter - * and setter methods. The getter method of a MethodProperty - * instantiated with this constructor will be called with no arguments, and - * the setter method with only the new value as the sole argument. - *

- * - *

- * If the setter method is null, the resulting - * MethodProperty will be read-only, otherwise it will be - * read-write. - *

- * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethodName - * the name of the getter method. - * @param setMethodName - * the name of the setter method. - * - */ - public MethodProperty(Class type, Object instance, - String getMethodName, String setMethodName) { - this(type, instance, getMethodName, setMethodName, new Object[] {}, - new Object[] { null }, 0); - } - - /** - *

- * Creates a new instance of MethodProperty with the getter and - * setter methods. The getter method of a MethodProperty - * instantiated with this constructor will be called with no arguments, and - * the setter method with only the new value as the sole argument. - *

- * - *

- * If the setter method is null, the resulting - * MethodProperty will be read-only, otherwise it will be - * read-write. - *

- * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethod - * the getter method. - * @param setMethod - * the setter method. - */ - public MethodProperty(Class type, Object instance, - Method getMethod, Method setMethod) { - this(type, instance, getMethod, setMethod, new Object[] {}, - new Object[] { null }, 0); - } - - /** - *

- * Creates a new instance of MethodProperty from named getter - * and setter methods and argument lists. The getter method of a - * MethodProperty instantiated with this constructor will be - * called with the getArgs as arguments. The setArgs will be used as the - * arguments for the setter method, though the argument indexed by the - * setArgumentIndex will be replaced with the argument passed to the - * {@link #setValue(Object newValue)} method. - *

- * - *

- * For example, if the setArgs contains A, - * B and C, and setArgumentIndex = - * 1, the call methodProperty.setValue(X) would result - * in the setter method to be called with the parameter set of - * {A, X, C} - *

- * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethodName - * the name of the getter method. - * @param setMethodName - * the name of the setter method. - * @param getArgs - * the fixed argument list to be passed to the getter method. - * @param setArgs - * the fixed argument list to be passed to the setter method. - * @param setArgumentIndex - * the index of the argument in setArgs to be - * replaced with newValue when - * {@link #setValue(Object newValue)} is called. - */ - @SuppressWarnings("unchecked") - public MethodProperty(Class type, Object instance, - String getMethodName, String setMethodName, Object[] getArgs, - Object[] setArgs, int setArgumentIndex) { - - // Check the setargs and setargs index - if (setMethodName != null && setArgs == null) { - throw new IndexOutOfBoundsException("The setArgs can not be null"); - } - if (setMethodName != null && (setArgumentIndex < 0 - || setArgumentIndex >= setArgs.length)) { - throw new IndexOutOfBoundsException( - "The setArgumentIndex must be >= 0 and < setArgs.length"); - } - - // Set type - this.type = type; - - // Find set and get -methods - final Method[] m = instance.getClass().getMethods(); - - // Finds get method - boolean found = false; - for (int i = 0; i < m.length; i++) { - - // Tests the name of the get Method - if (!m[i].getName().equals(getMethodName)) { - - // name does not match, try next method - continue; - } - - // Tests return type - if (!type.equals(m[i].getReturnType())) { - continue; - } - - // Tests the parameter types - final Class[] c = m[i].getParameterTypes(); - if (c.length != getArgs.length) { - - // not the right amount of parameters, try next method - continue; - } - int j = 0; - while (j < c.length) { - if (getArgs[j] != null - && !c[j].isAssignableFrom(getArgs[j].getClass())) { - - // parameter type does not match, try next method - break; - } - j++; - } - if (j == c.length) { - - // all paramteters matched - if (found == true) { - throw new MethodException(this, - "Could not uniquely identify " + getMethodName - + "-method"); - } else { - found = true; - getMethod = m[i]; - } - } - } - if (found != true) { - throw new MethodException(this, - "Could not find " + getMethodName + "-method"); - } - - // Finds set method - if (setMethodName != null) { - - // Finds setMethod - found = false; - for (int i = 0; i < m.length; i++) { - - // Checks name - if (!m[i].getName().equals(setMethodName)) { - - // name does not match, try next method - continue; - } - - // Checks parameter compatibility - final Class[] c = m[i].getParameterTypes(); - if (c.length != setArgs.length) { - - // not the right amount of parameters, try next method - continue; - } - int j = 0; - while (j < c.length) { - if (setArgs[j] != null - && !c[j].isAssignableFrom(setArgs[j].getClass())) { - - // parameter type does not match, try next method - break; - } else if (j == setArgumentIndex && !c[j].equals(type)) { - - // Property type is not the same as setArg type - break; - } - j++; - } - if (j == c.length) { - - // all parameters match - if (found == true) { - throw new MethodException(this, - "Could not identify unique " + setMethodName - + "-method"); - } else { - found = true; - setMethod = m[i]; - } - } - } - if (found != true) { - throw new MethodException(this, - "Could not identify " + setMethodName + "-method"); - } - } - - // Gets the return type from get method - this.type = (Class) convertPrimitiveType(type); - - setArguments(getArgs, setArgs, setArgumentIndex); - this.instance = instance; - } - - /** - *

- * Creates a new instance of MethodProperty from the getter and - * setter methods, and argument lists. - *

- *

- * This constructor behaves exactly like - * {@link #MethodProperty(Class type, Object instance, String getMethodName, String setMethodName, Object [] getArgs, Object [] setArgs, int setArgumentIndex)} - * except that instead of names of the getter and setter methods this - * constructor is given the actual methods themselves. - *

- * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethod - * the getter method. - * @param setMethod - * the setter method. - * @param getArgs - * the fixed argument list to be passed to the getter method. - * @param setArgs - * the fixed argument list to be passed to the setter method. - * @param setArgumentIndex - * the index of the argument in setArgs to be - * replaced with newValue when - * {@link #setValue(Object newValue)} is called. - */ - @SuppressWarnings("unchecked") - // cannot use "Class" because of automatic primitive type - // conversions - public MethodProperty(Class type, Object instance, Method getMethod, - Method setMethod, Object[] getArgs, Object[] setArgs, - int setArgumentIndex) { - - if (getMethod == null) { - throw new MethodException(this, - "Property GET-method cannot not be null: " + type); - } - - if (setMethod != null) { - if (setArgs == null) { - throw new IndexOutOfBoundsException( - "The setArgs can not be null"); - } - if (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length) { - throw new IndexOutOfBoundsException( - "The setArgumentIndex must be >= 0 and < setArgs.length"); - } - } - - // Gets the return type from get method - Class convertedType = (Class) convertPrimitiveType( - type); - - this.getMethod = getMethod; - this.setMethod = setMethod; - setArguments(getArgs, setArgs, setArgumentIndex); - this.instance = instance; - this.type = convertedType; - } - - /** - * Find a getter method for a property (getXyz(), isXyz() or areXyz()). - * - * @param propertyName - * name of the property - * @param beanClass - * class in which to look for the getter methods - * @return Method - * @throws NoSuchMethodException - * if no getter found - */ - static Method initGetterMethod(String propertyName, - final Class beanClass) throws NoSuchMethodException { - propertyName = SharedUtil.capitalize(propertyName); - - Method getMethod = null; - try { - getMethod = beanClass.getMethod("get" + propertyName, - new Class[] {}); - } catch (final java.lang.NoSuchMethodException ignored) { - try { - getMethod = beanClass.getMethod("is" + propertyName, - new Class[] {}); - } catch (final java.lang.NoSuchMethodException ignoredAsWell) { - getMethod = beanClass.getMethod("are" + propertyName, - new Class[] {}); - } - } - return getMethod; - } - - /** - * Returns the type of the Property. The methods getValue and - * setValue must be compatible with this type: one must be able - * to safely cast the value returned from getValue to the given - * type and pass any variable assignable to this type as an argument to - * setValue. - * - * @return type of the Property - */ - @Override - public final Class getType() { - return type; - } - - /** - * Tests if the object is in read-only mode. In read-only mode calls to - * setValue will throw ReadOnlyException and will - * not modify the value of the Property. - * - * @return true if the object is in read-only mode, - * false if it's not - */ - @Override - public boolean isReadOnly() { - return super.isReadOnly() || (setMethod == null); - } - - /** - * Gets the value stored in the Property. The value is resolved by calling - * the specified getter method with the argument specified at instantiation. - * - * @return the value of the Property - */ - @Override - public T getValue() { - try { - if (instance == null) { - return null; - } else { - return (T) getMethod.invoke(instance, getArgs); - } - } catch (final Throwable e) { - throw new MethodException(this, e); - } - } - - /** - *

- * Sets the setter method and getter method argument lists. - *

- * - * @param getArgs - * the fixed argument list to be passed to the getter method. - * @param setArgs - * the fixed argument list to be passed to the setter method. - * @param setArgumentIndex - * the index of the argument in setArgs to be - * replaced with newValue when - * {@link #setValue(Object newValue)} is called. - */ - public void setArguments(Object[] getArgs, Object[] setArgs, - int setArgumentIndex) { - if (getArgs.length == 0) { - this.getArgs = DEFAULT_GET_ARGS; - } else { - this.getArgs = Arrays.copyOf(getArgs, getArgs.length); - } - if (Arrays.equals(setArgs, DEFAULT_SET_ARGS)) { - this.setArgs = DEFAULT_SET_ARGS; - } else { - this.setArgs = Arrays.copyOf(setArgs, setArgs.length); - } - this.setArgumentIndex = setArgumentIndex; - } - - /** - * Sets the value of the property. - * - * Note that since Vaadin 7, no conversions are performed and the value must - * be of the correct type. - * - * @param newValue - * the New value of the property. - * @throws Property.ReadOnlyException - * if the object is in read-only mode. - * @see #invokeSetMethod(Object) - */ - @Override - public void setValue(T newValue) throws Property.ReadOnlyException { - - // Checks the mode - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - invokeSetMethod(newValue); - fireValueChange(); - } - - /** - * Internal method to actually call the setter method of the wrapped - * property. - * - * @param value - */ - protected void invokeSetMethod(T value) { - - try { - // Construct a temporary argument array only if needed - if (setArgs.length == 1) { - setMethod.invoke(instance, new Object[] { value }); - } else { - - // Sets the value to argument array - final Object[] args = new Object[setArgs.length]; - for (int i = 0; i < setArgs.length; i++) { - args[i] = (i == setArgumentIndex) ? value : setArgs[i]; - } - setMethod.invoke(instance, args); - } - } catch (final InvocationTargetException e) { - final Throwable targetException = e.getTargetException(); - throw new MethodException(this, targetException); - } catch (final Exception e) { - throw new MethodException(this, e); - } - } - - /** - * Exception object that signals that there were problems - * calling or finding the specified getter or setter methods of the - * property. - * - * @author Vaadin Ltd. - * @since 3.0 - */ - @SuppressWarnings("rawtypes") - // Exceptions cannot be parameterized, ever. - public static class MethodException extends RuntimeException { - - /** - * The method property from which the exception originates from - */ - private final Property property; - - /** - * Cause of the method exception - */ - private Throwable cause; - - /** - * Constructs a new MethodException with the specified - * detail message. - * - * @param property - * the property. - * @param msg - * the detail message. - */ - public MethodException(Property property, String msg) { - super(msg); - this.property = property; - } - - /** - * Constructs a new MethodException from another exception. - * - * @param property - * the property. - * @param cause - * the cause of the exception. - */ - public MethodException(Property property, Throwable cause) { - this.property = property; - this.cause = cause; - } - - /** - * @see java.lang.Throwable#getCause() - */ - @Override - public Throwable getCause() { - return cause; - } - - /** - * Gets the method property this exception originates from. - * - * @return MethodProperty or null if not a valid MethodProperty - */ - public MethodProperty getMethodProperty() { - return (property instanceof MethodProperty) - ? (MethodProperty) property : null; - } - - /** - * Gets the method property this exception originates from. - * - * @return Property from which the exception originates - */ - public Property getProperty() { - return property; - } - } - - /** - * Sends a value change event to all registered listeners. - * - * Public for backwards compatibility, visibility may be reduced in future - * versions. - */ - @Override - public void fireValueChange() { - super.fireValueChange(); - } - - private static final Logger getLogger() { - return Logger.getLogger(MethodProperty.class.getName()); - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java b/server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java deleted file mode 100644 index dfffb5b189..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/MethodPropertyDescriptor.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.util.ReflectTools; -import com.vaadin.util.SerializerHelper; -import com.vaadin.v7.data.Property; - -/** - * Property descriptor that is able to create simple {@link MethodProperty} - * instances for a bean, using given accessors. - * - * @param - * bean type - * - * @since 6.6 - */ -public class MethodPropertyDescriptor - implements VaadinPropertyDescriptor { - - private final String name; - private Class propertyType; - private transient Method readMethod; - private transient Method writeMethod; - - /** - * Creates a property descriptor that can create MethodProperty instances to - * access the underlying bean property. - * - * @param name - * of the property - * @param propertyType - * type (class) of the property - * @param readMethod - * getter {@link Method} for the property - * @param writeMethod - * setter {@link Method} for the property or null if read-only - * property - */ - public MethodPropertyDescriptor(String name, Class propertyType, - Method readMethod, Method writeMethod) { - this.name = name; - this.propertyType = ReflectTools.convertPrimitiveType(propertyType); - this.readMethod = readMethod; - this.writeMethod = writeMethod; - } - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) - throws IOException { - out.defaultWriteObject(); - SerializerHelper.writeClass(out, propertyType); - - if (writeMethod != null) { - out.writeObject(writeMethod.getName()); - SerializerHelper.writeClass(out, writeMethod.getDeclaringClass()); - SerializerHelper.writeClassArray(out, - writeMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - out.writeObject(null); - } - - if (readMethod != null) { - out.writeObject(readMethod.getName()); - SerializerHelper.writeClass(out, readMethod.getDeclaringClass()); - SerializerHelper.writeClassArray(out, - readMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - out.writeObject(null); - } - } - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - try { - @SuppressWarnings("unchecked") - // business assumption; type parameters not checked at runtime - Class class1 = (Class) SerializerHelper.readClass(in); - propertyType = ReflectTools.convertPrimitiveType(class1); - - String name = (String) in.readObject(); - Class writeMethodClass = SerializerHelper.readClass(in); - Class[] paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { - writeMethod = writeMethodClass.getMethod(name, paramTypes); - } else { - writeMethod = null; - } - - name = (String) in.readObject(); - Class readMethodClass = SerializerHelper.readClass(in); - paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { - readMethod = readMethodClass.getMethod(name, paramTypes); - } else { - readMethod = null; - } - } catch (SecurityException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } catch (NoSuchMethodException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } - } - - @Override - public String getName() { - return name; - } - - @Override - public Class getPropertyType() { - return propertyType; - } - - @Override - public Property createProperty(Object bean) { - return new MethodProperty(propertyType, bean, readMethod, - writeMethod); - } - - private static final Logger getLogger() { - return Logger.getLogger(MethodPropertyDescriptor.class.getName()); - } -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java b/server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java deleted file mode 100644 index 38bf7300aa..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/NestedMethodProperty.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import static com.vaadin.util.ReflectTools.convertPrimitiveType; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.vaadin.shared.util.SharedUtil; -import com.vaadin.v7.data.Property; -import com.vaadin.v7.data.util.MethodProperty.MethodException; - -/** - * Nested accessor based property for a bean. - * - * The property is specified in the dotted notation, e.g. "address.street", and - * can contain multiple levels of nesting. - * - * When accessing the property value, all intermediate getters must exist and - * should return non-null values when the property value is accessed. If an - * intermediate getter returns null, a null value will be returned. - * - * @see MethodProperty - * - * @since 6.6 - */ -public class NestedMethodProperty extends AbstractProperty { - - // needed for de-serialization - private String propertyName; - - // chain of getter methods - private transient List getMethods; - /** - * The setter method. - */ - private transient Method setMethod; - - /** - * Bean instance used as a starting point for accessing the property value. - */ - private Object instance; - - private Class type; - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) - throws IOException { - out.defaultWriteObject(); - // getMethods and setMethod are reconstructed on read based on - // propertyName - } - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - - initialize(instance.getClass(), propertyName); - } - - /** - * Constructs a nested method property for a given object instance. The - * property name is a dot separated string pointing to a nested property, - * e.g. "manager.address.street". - *

- * Calling getValue will return null if any intermediate getter returns null - * - * @param instance - * top-level bean to which the property applies - * @param propertyName - * dot separated nested property name - * @throws IllegalArgumentException - * if the property name is invalid - */ - public NestedMethodProperty(Object instance, String propertyName) { - this.instance = instance; - initialize(instance.getClass(), propertyName); - } - - /** - * For internal use to deduce property type etc. without a bean instance. - * Calling {@link #setValue(Object)} or {@link #getValue()} on properties - * constructed this way is not supported. - * - * @param instanceClass - * class of the top-level bean - * @param propertyName - */ - NestedMethodProperty(Class instanceClass, String propertyName) { - instance = null; - initialize(instanceClass, propertyName); - } - - /** - * Initializes most of the internal fields based on the top-level bean - * instance and property name (dot-separated string). - * - * @param beanClass - * class of the top-level bean to which the property applies - * @param propertyName - * dot separated nested property name - * @throws IllegalArgumentException - * if the property name is invalid - */ - private void initialize(Class beanClass, String propertyName) - throws IllegalArgumentException { - - List getMethods = new ArrayList(); - - String lastSimplePropertyName = propertyName; - Class lastClass = beanClass; - - // first top-level property, then go deeper in a loop - Class propertyClass = beanClass; - String[] simplePropertyNames = propertyName.split("\\."); - if (propertyName.endsWith(".") || 0 == simplePropertyNames.length) { - throw new IllegalArgumentException( - "Invalid property name '" + propertyName + "'"); - } - for (int i = 0; i < simplePropertyNames.length; i++) { - String simplePropertyName = simplePropertyNames[i].trim(); - if (simplePropertyName.length() > 0) { - lastSimplePropertyName = simplePropertyName; - lastClass = propertyClass; - try { - Method getter = MethodProperty.initGetterMethod( - simplePropertyName, propertyClass); - propertyClass = getter.getReturnType(); - getMethods.add(getter); - } catch (final java.lang.NoSuchMethodException e) { - throw new IllegalArgumentException("Bean property '" - + simplePropertyName + "' not found", e); - } - } else { - throw new IllegalArgumentException( - "Empty or invalid bean property identifier in '" - + propertyName + "'"); - } - } - - // In case the get method is found, resolve the type - Method lastGetMethod = getMethods.get(getMethods.size() - 1); - Class type = lastGetMethod.getReturnType(); - - // Finds the set method - Method setMethod = null; - try { - // Assure that the first letter is upper cased (it is a common - // mistake to write firstName, not FirstName). - lastSimplePropertyName = SharedUtil - .capitalize(lastSimplePropertyName); - - setMethod = lastClass.getMethod("set" + lastSimplePropertyName, - new Class[] { type }); - } catch (final NoSuchMethodException skipped) { - } - - this.type = (Class) convertPrimitiveType(type); - this.propertyName = propertyName; - this.getMethods = getMethods; - this.setMethod = setMethod; - } - - @Override - public Class getType() { - return type; - } - - @Override - public boolean isReadOnly() { - return super.isReadOnly() || (null == setMethod); - } - - /** - * Gets the value stored in the Property. The value is resolved by calling - * the specified getter method with the argument specified at instantiation. - * - * @return the value of the Property - */ - @Override - public T getValue() { - try { - Object object = instance; - for (Method m : getMethods) { - object = m.invoke(object); - if (object == null) { - return null; - } - } - return (T) object; - } catch (final Throwable e) { - throw new MethodException(this, e); - } - } - - /** - * Sets the value of the property. The new value must be assignable to the - * type of this property. - * - * @param newValue - * the New value of the property. - * @throws Property.ReadOnlyException - * if the object is in read-only mode. - * @see #invokeSetMethod(Object) - */ - @Override - public void setValue(T newValue) throws ReadOnlyException { - // Checks the mode - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - invokeSetMethod(newValue); - fireValueChange(); - } - - /** - * Internal method to actually call the setter method of the wrapped - * property. - * - * @param value - */ - protected void invokeSetMethod(T value) { - try { - Object object = instance; - for (int i = 0; i < getMethods.size() - 1; i++) { - object = getMethods.get(i).invoke(object); - } - setMethod.invoke(object, new Object[] { value }); - } catch (final InvocationTargetException e) { - throw new MethodException(this, e.getTargetException()); - } catch (final Exception e) { - throw new MethodException(this, e); - } - } - - /** - * Returns an unmodifiable list of getter methods to call in sequence to get - * the property value. - * - * This API may change in future versions. - * - * @return unmodifiable list of getter methods corresponding to each segment - * of the property name - */ - protected List getGetMethods() { - return Collections.unmodifiableList(getMethods); - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java b/server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java deleted file mode 100644 index 7bbf6253a5..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/NestedPropertyDescriptor.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import com.vaadin.v7.data.Property; - -/** - * Property descriptor that is able to create nested property instances for a - * bean. - * - * The property is specified in the dotted notation, e.g. "address.street", and - * can contain multiple levels of nesting. - * - * @param - * bean type - * - * @since 6.6 - */ -public class NestedPropertyDescriptor - implements VaadinPropertyDescriptor { - - private final String name; - private final Class propertyType; - - /** - * Creates a property descriptor that can create MethodProperty instances to - * access the underlying bean property. - * - * @param name - * of the property in a dotted path format, e.g. "address.street" - * @param beanType - * type (class) of the top-level bean - * @throws IllegalArgumentException - * if the property name is invalid - */ - public NestedPropertyDescriptor(String name, Class beanType) - throws IllegalArgumentException { - this.name = name; - NestedMethodProperty property = new NestedMethodProperty( - beanType, name); - this.propertyType = property.getType(); - } - - @Override - public String getName() { - return name; - } - - @Override - public Class getPropertyType() { - return propertyType; - } - - @Override - public Property createProperty(BT bean) { - return new NestedMethodProperty(bean, name); - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java b/server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java deleted file mode 100644 index cd9f6c36c7..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/ObjectProperty.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import com.vaadin.v7.data.Property; - -/** - * A simple data object containing one typed value. This class is a - * straightforward implementation of the the {@link com.vaadin.v7.data.Property} - * interface. - * - * @author Vaadin Ltd. - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ObjectProperty extends AbstractProperty { - - /** - * The value contained by the Property. - */ - private T value; - - /** - * Data type of the Property's value. - */ - private final Class type; - - /** - * Creates a new instance of ObjectProperty with the given value. The type - * of the property is automatically initialized to be the type of the given - * value. - * - * @param value - * the Initial value of the Property. - */ - @SuppressWarnings("unchecked") - // the cast is safe, because an object of type T has class Class - public ObjectProperty(T value) { - this(value, (Class) value.getClass()); - } - - /** - * Creates a new instance of ObjectProperty with the given value and type. - * - * Since Vaadin 7, only values of the correct type are accepted, and no - * automatic conversions are performed. - * - * @param value - * the Initial value of the Property. - * @param type - * the type of the value. The value must be assignable to given - * type. - */ - public ObjectProperty(T value, Class type) { - - // Set the values - this.type = type; - setValue(value); - } - - /** - * Creates a new instance of ObjectProperty with the given value, type and - * read-only mode status. - * - * Since Vaadin 7, only the correct type of values is accepted, see - * {@link #ObjectProperty(Object, Class)}. - * - * @param value - * the Initial value of the property. - * @param type - * the type of the value. value must be assignable - * to this type. - * @param readOnly - * Sets the read-only mode. - */ - public ObjectProperty(T value, Class type, boolean readOnly) { - this(value, type); - setReadOnly(readOnly); - } - - /** - * Returns the type of the ObjectProperty. The methods getValue - * and setValue must be compatible with this type: one must be - * able to safely cast the value returned from getValue to the - * given type and pass any variable assignable to this type as an argument - * to setValue. - * - * @return type of the Property - */ - @Override - public final Class getType() { - return type; - } - - /** - * Gets the value stored in the Property. - * - * @return the value stored in the Property - */ - @Override - public T getValue() { - return value; - } - - /** - * Sets the value of the property. - * - * Note that since Vaadin 7, no conversions are performed and the value must - * be of the correct type. - * - * @param newValue - * the New value of the property. - * @throws Property.ReadOnlyException - * if the object is in read-only mode - */ - @Override - public void setValue(T newValue) throws Property.ReadOnlyException { - - // Checks the mode - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - this.value = newValue; - - fireValueChange(); - } -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java b/server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java deleted file mode 100644 index c95f97a1f1..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/PropertyFormatter.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import com.vaadin.v7.data.Property; -import com.vaadin.v7.data.util.converter.Converter; - -/** - * Formatting proxy for a {@link Property}. - * - *

- * This class can be used to implement formatting for any type of Property - * datasources. The idea is to connect this as proxy between UI component and - * the original datasource. - *

- * - *

- * For example - *

textfield.setPropertyDataSource(new PropertyFormatter(property) {
-            public String format(Object value) {
-                return ((Double) value).toString() + "000000000";
-            }
-
-            public Object parse(String formattedValue) throws Exception {
-                return Double.parseDouble(formattedValue);
-            }
-
-        });
adds formatter for Double-typed property that extends - * standard "1.0" notation with more zeroes. - *

- * - * @param T - * type of the underlying property (a PropertyFormatter is always a - * Property<String>) - * - * @deprecated As of 7.0, replaced by {@link Converter} - * @author Vaadin Ltd. - * @since 5.3.0 - */ -@SuppressWarnings("serial") -@Deprecated -public abstract class PropertyFormatter extends AbstractProperty - implements Property.Viewer, Property.ValueChangeListener, - Property.ReadOnlyStatusChangeListener { - - /** Datasource that stores the actual value. */ - Property dataSource; - - /** - * Construct a new {@code PropertyFormatter} that is not connected to any - * data source. Call {@link #setPropertyDataSource(Property)} later on to - * attach it to a property. - * - */ - protected PropertyFormatter() { - } - - /** - * Construct a new formatter that is connected to given data source. Calls - * {@link #format(Object)} which can be a problem if the formatter has not - * yet been initialized. - * - * @param propertyDataSource - * to connect this property to. - */ - public PropertyFormatter(Property propertyDataSource) { - - setPropertyDataSource(propertyDataSource); - } - - /** - * Gets the current data source of the formatter, if any. - * - * @return the current data source as a Property, or null if - * none defined. - */ - @Override - public Property getPropertyDataSource() { - return dataSource; - } - - /** - * Sets the specified Property as the data source for the formatter. - * - * - *

- * Remember that new data sources getValue() must return objects that are - * compatible with parse() and format() methods. - *

- * - * @param newDataSource - * the new data source Property. - */ - @Override - public void setPropertyDataSource(Property newDataSource) { - - boolean readOnly = false; - String prevValue = null; - - if (dataSource != null) { - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource) - .removeListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .removeListener(this); - } - readOnly = isReadOnly(); - prevValue = getValue(); - } - - dataSource = newDataSource; - - if (dataSource != null) { - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .addListener(this); - } - } - - if (isReadOnly() != readOnly) { - fireReadOnlyStatusChange(); - } - String newVal = getValue(); - if ((prevValue == null && newVal != null) - || (prevValue != null && !prevValue.equals(newVal))) { - fireValueChange(); - } - } - - /* Documented in the interface */ - @Override - public Class getType() { - return String.class; - } - - /** - * Get the formatted value. - * - * @return If the datasource returns null, this is null. Otherwise this is - * String given by format(). - */ - @Override - public String getValue() { - T value = dataSource == null ? null : dataSource.getValue(); - if (value == null) { - return null; - } - return format(value); - } - - /** Reflects the read-only status of the datasource. */ - @Override - public boolean isReadOnly() { - return dataSource == null ? false : dataSource.isReadOnly(); - } - - /** - * This method must be implemented to format the values received from - * DataSource. - * - * @param value - * Value object got from the datasource. This is guaranteed to be - * non-null and of the type compatible with getType() of the - * datasource. - * @return - */ - abstract public String format(T value); - - /** - * Parse string and convert it to format compatible with datasource. - * - * The method is required to assure that parse(format(x)) equals x. - * - * @param formattedValue - * This is guaranteed to be non-null string. - * @return Non-null value compatible with datasource. - * @throws Exception - * Any type of exception can be thrown to indicate that the - * conversion was not succesful. - */ - abstract public T parse(String formattedValue) throws Exception; - - /** - * Sets the Property's read-only mode to the specified status. - * - * @param newStatus - * the new read-only status of the Property. - */ - @Override - public void setReadOnly(boolean newStatus) { - if (dataSource != null) { - dataSource.setReadOnly(newStatus); - } - } - - @Override - public void setValue(String newValue) throws ReadOnlyException { - if (dataSource == null) { - return; - } - if (newValue == null) { - if (dataSource.getValue() != null) { - dataSource.setValue(null); - fireValueChange(); - } - } else { - try { - dataSource.setValue(parse(newValue.toString())); - if (!newValue.equals(getValue())) { - fireValueChange(); - } - } catch (Exception e) { - throw new IllegalArgumentException("Could not parse value", e); - } - } - } - - /** - * Listens for changes in the datasource. - * - * This should not be called directly. - */ - @Override - public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { - fireValueChange(); - } - - /** - * Listens for changes in the datasource. - * - * This should not be called directly. - */ - @Override - public void readOnlyStatusChange( - com.vaadin.v7.data.Property.ReadOnlyStatusChangeEvent event) { - fireReadOnlyStatusChange(); - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java b/server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java deleted file mode 100644 index ce5bed8968..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/TextFileProperty.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.Charset; - -/** - * Property implementation for wrapping a text file. - * - * Supports reading and writing of a File from/to String. - * - * {@link ValueChangeListener}s are supported, but only fire when - * setValue(Object) is explicitly called. {@link ReadOnlyStatusChangeListener}s - * are supported but only fire when setReadOnly(boolean) is explicitly called. - * - */ -@SuppressWarnings("serial") -public class TextFileProperty extends AbstractProperty { - - private File file; - private Charset charset = null; - - /** - * Wrap given file with property interface. - * - * Setting the file to null works, but getValue() will return null. - * - * @param file - * File to be wrapped. - */ - public TextFileProperty(File file) { - this.file = file; - } - - /** - * Wrap the given file with the property interface and specify character - * set. - * - * Setting the file to null works, but getValue() will return null. - * - * @param file - * File to be wrapped. - * @param charset - * Charset to be used for reading and writing the file. - */ - public TextFileProperty(File file, Charset charset) { - this.file = file; - this.charset = charset; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getType() - */ - @Override - public Class getType() { - return String.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getValue() - */ - @Override - public String getValue() { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - InputStreamReader isr = charset == null ? new InputStreamReader(fis) - : new InputStreamReader(fis, charset); - BufferedReader r = new BufferedReader(isr); - StringBuilder b = new StringBuilder(); - char buf[] = new char[8 * 1024]; - int len; - while ((len = r.read(buf)) != -1) { - b.append(buf, 0, len); - } - r.close(); - isr.close(); - fis.close(); - return b.toString(); - } catch (FileNotFoundException e) { - return null; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#isReadOnly() - */ - @Override - public boolean isReadOnly() { - return file == null || super.isReadOnly() || !file.canWrite(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#setValue(java.lang.Object) - */ - @Override - public void setValue(String newValue) throws ReadOnlyException { - if (isReadOnly()) { - throw new ReadOnlyException(); - } - if (file == null) { - return; - } - - try { - FileOutputStream fos = new FileOutputStream(file); - OutputStreamWriter osw = charset == null - ? new OutputStreamWriter(fos) - : new OutputStreamWriter(fos, charset); - BufferedWriter w = new BufferedWriter(osw); - w.append(newValue.toString()); - w.flush(); - w.close(); - osw.close(); - fos.close(); - fireValueChange(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java b/server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java deleted file mode 100644 index 21afa4bc92..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/TransactionalPropertyWrapper.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import com.vaadin.v7.data.Property; -import com.vaadin.v7.data.Property.ValueChangeEvent; -import com.vaadin.v7.data.Property.ValueChangeNotifier; - -/** - * Wrapper class that helps implement two-phase commit for a non-transactional - * property. - * - * When accessing the property through the wrapper, getting and setting the - * property value take place immediately. However, the wrapper keeps track of - * the old value of the property so that it can be set for the property in case - * of a roll-back. This can result in the underlying property value changing - * multiple times (first based on modifications made by the application, then - * back upon roll-back). - * - * Value change events on the {@link TransactionalPropertyWrapper} are only - * fired at the end of a successful transaction, whereas listeners attached to - * the underlying property may receive multiple value change events. - * - * @see com.vaadin.v7.data.Property.Transactional - * - * @author Vaadin Ltd - * @since 7.0 - * - * @param - */ -public class TransactionalPropertyWrapper extends AbstractProperty - implements ValueChangeNotifier, Property.Transactional { - - private Property wrappedProperty; - private boolean inTransaction = false; - private boolean valueChangePending; - private T valueBeforeTransaction; - private final ValueChangeListener listener = new ValueChangeListener() { - - @Override - public void valueChange(ValueChangeEvent event) { - fireValueChange(); - } - }; - - public TransactionalPropertyWrapper(Property wrappedProperty) { - this.wrappedProperty = wrappedProperty; - if (wrappedProperty instanceof ValueChangeNotifier) { - ((ValueChangeNotifier) wrappedProperty) - .addValueChangeListener(listener); - } - } - - /** - * Removes the ValueChangeListener from wrapped Property that was added by - * TransactionalPropertyWrapper. - * - * @since 7.1.15 - */ - public void detachFromProperty() { - if (wrappedProperty instanceof ValueChangeNotifier) { - ((ValueChangeNotifier) wrappedProperty) - .removeValueChangeListener(listener); - } - } - - @Override - public Class getType() { - return wrappedProperty.getType(); - } - - @Override - public T getValue() { - return wrappedProperty.getValue(); - } - - @Override - public void setValue(T newValue) throws ReadOnlyException { - // Causes a value change to be sent to this listener which in turn fires - // a new value change event for this property - wrappedProperty.setValue(newValue); - } - - @Override - public void startTransaction() { - inTransaction = true; - valueBeforeTransaction = getValue(); - } - - @Override - public void commit() { - endTransaction(); - } - - @Override - public void rollback() { - try { - wrappedProperty.setValue(valueBeforeTransaction); - } finally { - valueChangePending = false; - endTransaction(); - } - } - - protected void endTransaction() { - inTransaction = false; - valueBeforeTransaction = null; - if (valueChangePending) { - fireValueChange(); - } - } - - @Override - protected void fireValueChange() { - if (inTransaction) { - valueChangePending = true; - } else { - super.fireValueChange(); - } - } - - public Property getWrappedProperty() { - return wrappedProperty; - } - - @Override - public boolean isReadOnly() { - return wrappedProperty.isReadOnly(); - } - - @Override - public void setReadOnly(boolean newStatus) { - boolean oldStatus = isReadOnly(); - wrappedProperty.setReadOnly(newStatus); - if (oldStatus != isReadOnly()) { - fireReadOnlyStatusChange(); - } - } - -} diff --git a/server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java b/server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java deleted file mode 100644 index 71c562d425..0000000000 --- a/server/src/main/java/com/vaadin/v7/data/util/VaadinPropertyDescriptor.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2000-2016 Vaadin Ltd. - * - * 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 com.vaadin.v7.data.util; - -import java.io.Serializable; - -import com.vaadin.v7.data.Property; - -/** - * Property descriptor that can create a property instance for a bean. - * - * Used by {@link BeanItem} and {@link AbstractBeanContainer} to keep track of - * the set of properties of items. - * - * @param - * bean type - * - * @since 6.6 - */ -public interface VaadinPropertyDescriptor extends Serializable { - /** - * Returns the name of the property. - * - * @return - */ - public String getName(); - - /** - * Returns the type of the property. - * - * @return Class - */ - public Class getPropertyType(); - - /** - * Creates a new {@link Property} instance for this property for a bean. - * - * @param bean - * @return - */ - public Property createProperty(BT bean); -} diff --git a/server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java b/server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java deleted file mode 100644 index 854f3666ac..0000000000 --- a/server/src/test/java/com/vaadin/tests/server/AbstractPropertyListenersTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.vaadin.tests.server; - -import org.junit.Test; - -import com.vaadin.tests.server.component.AbstractListenerMethodsTestBase; -import com.vaadin.v7.data.Property.ReadOnlyStatusChangeEvent; -import com.vaadin.v7.data.Property.ReadOnlyStatusChangeListener; -import com.vaadin.v7.data.Property.ValueChangeEvent; -import com.vaadin.v7.data.Property.ValueChangeListener; -import com.vaadin.v7.data.util.AbstractProperty; -import com.vaadin.v7.data.util.ObjectProperty; - -public class AbstractPropertyListenersTest - extends AbstractListenerMethodsTestBase { - - @Test - public void testValueChangeListenerAddGetRemove() throws Exception { - testListenerAddGetRemove(AbstractProperty.class, ValueChangeEvent.class, - ValueChangeListener.class, new ObjectProperty("")); - } - - @Test - public void testReadOnlyStatusChangeListenerAddGetRemove() - throws Exception { - testListenerAddGetRemove(AbstractProperty.class, - ReadOnlyStatusChangeEvent.class, - ReadOnlyStatusChangeListener.class, - new ObjectProperty("")); - } -} diff --git a/server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java b/server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java deleted file mode 100644 index 775018642a..0000000000 --- a/server/src/test/java/com/vaadin/tests/server/PropertyFormatterTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.vaadin.tests.server; - -import static org.junit.Assert.assertTrue; - -import java.util.Date; - -import org.junit.Test; - -import com.vaadin.v7.data.util.ObjectProperty; -import com.vaadin.v7.data.util.PropertyFormatter; - -@SuppressWarnings("unchecked") -public class PropertyFormatterTest { - - class TestFormatter extends PropertyFormatter { - - @Override - public String format(Object value) { - boolean isCorrectType = getExpectedClass() - .isAssignableFrom(value.getClass()); - assertTrue(isCorrectType); - return "FOO"; - } - - @Override - public Object parse(String formattedValue) throws Exception { - return getExpectedClass().newInstance(); - } - } - - @SuppressWarnings("rawtypes") - private Class expectedClass; - - @SuppressWarnings("rawtypes") - private Class getExpectedClass() { - return expectedClass; - } - - /** - * The object passed to format should be same as property's type. - * - * @throws IllegalAccessException - * @throws InstantiationException - */ - @Test - @SuppressWarnings({ "rawtypes" }) - public void testCorrectTypeForFormat() - throws InstantiationException, IllegalAccessException { - Class[] testedTypes = new Class[] { Integer.class, Boolean.class, - Double.class, String.class, Date.class }; - Object[] testValues = new Object[] { new Integer(3), Boolean.FALSE, - new Double(3.3), "bar", new Date() }; - - int i = 0; - for (Class class1 : testedTypes) { - expectedClass = class1; - - TestFormatter formatter = new TestFormatter(); - - // Should just return null, without formatting - Object value = formatter.getValue(); - - // test with property which value is null - formatter.setPropertyDataSource( - new ObjectProperty(null, expectedClass)); - formatter.getValue(); // calls format - - // test with a value - formatter.setPropertyDataSource( - new ObjectProperty(testValues[i++], expectedClass)); - formatter.getValue(); // calls format - } - - } -} diff --git a/server/src/test/java/com/vaadin/tests/server/component/button/ButtonClickTest.java b/server/src/test/java/com/vaadin/tests/server/component/button/ButtonClickTest.java index 3d6a6136dc..9ffc861373 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/button/ButtonClickTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/button/ButtonClickTest.java @@ -1,5 +1,7 @@ package com.vaadin.tests.server.component.button; +import java.util.concurrent.atomic.AtomicInteger; + import org.junit.Assert; import org.junit.Test; @@ -7,7 +9,6 @@ import com.vaadin.server.VaadinRequest; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; -import com.vaadin.v7.data.util.ObjectProperty; import com.vaadin.ui.UI; /** @@ -19,17 +20,17 @@ public class ButtonClickTest { @Test public void clickDetachedButton() { Button b = new Button(); - final ObjectProperty counter = new ObjectProperty(0); + AtomicInteger counter = new AtomicInteger(0); b.addClickListener(new ClickListener() { @Override public void buttonClick(ClickEvent event) { - counter.setValue(counter.getValue() + 1); + counter.incrementAndGet(); } }); b.click(); - Assert.assertEquals(Integer.valueOf(1), counter.getValue()); + Assert.assertEquals(1, counter.get()); } @Test -- cgit v1.2.3