summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/src')
-rw-r--r--server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java37
-rw-r--r--server/src/com/vaadin/data/fieldgroup/FieldGroup.java93
-rw-r--r--server/src/com/vaadin/server/AbstractCommunicationManager.java17
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java15
4 files changed, 139 insertions, 23 deletions
diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
index 7e44c26c9e..55bd3a4641 100644
--- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
+++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
@@ -58,6 +58,23 @@ public class BeanFieldGroup<T> extends FieldGroup {
}
}
+ @Override
+ protected Object findPropertyId(java.lang.reflect.Field memberField) {
+ String fieldName = memberField.getName();
+ Item dataSource = getItemDataSource();
+ if (dataSource != null && dataSource.getItemProperty(fieldName) != null) {
+ return fieldName;
+ } else {
+ String minifiedFieldName = minifyFieldName(fieldName);
+ try {
+ return getFieldName(beanType, minifiedFieldName);
+ } catch (SecurityException e) {
+ } catch (NoSuchFieldException e) {
+ }
+ }
+ return null;
+ }
+
private static java.lang.reflect.Field getField(Class<?> cls,
String propertyId) throws SecurityException, NoSuchFieldException {
if (propertyId.contains(".")) {
@@ -75,7 +92,7 @@ public class BeanFieldGroup<T> extends FieldGroup {
} catch (NoSuchFieldError e) {
// Try super classes until we reach Object
Class<?> superClass = cls.getSuperclass();
- if (superClass != Object.class) {
+ if (superClass != null && superClass != Object.class) {
return getField(superClass, propertyId);
} else {
throw e;
@@ -84,6 +101,22 @@ public class BeanFieldGroup<T> extends FieldGroup {
}
}
+ private static String getFieldName(Class<?> cls, String propertyId)
+ throws SecurityException, NoSuchFieldException {
+ for (java.lang.reflect.Field field1 : cls.getDeclaredFields()) {
+ if (propertyId.equals(minifyFieldName(field1.getName()))) {
+ return field1.getName();
+ }
+ }
+ // Try super classes until we reach Object
+ Class<?> superClass = cls.getSuperclass();
+ if (superClass != null && superClass != Object.class) {
+ return getFieldName(superClass, propertyId);
+ } else {
+ throw new NoSuchFieldException();
+ }
+ }
+
/**
* Helper method for setting the data source directly using a bean. This
* method wraps the bean in a {@link BeanItem} and calls
@@ -166,4 +199,4 @@ public class BeanFieldGroup<T> extends FieldGroup {
}
return beanValidationImplementationAvailable;
}
-} \ No newline at end of file
+}
diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
index dc1fdbb78d..6c515dbdee 100644
--- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
+++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
@@ -733,11 +733,12 @@ public class FieldGroup implements Serializable {
* that have not been initialized.
* <p>
* This method processes all (Java) member fields whose type extends
- * {@link Field} and that can be mapped to a property id. Property id
- * mapping is done based on the field name or on a @{@link PropertyId}
- * annotation on the field. Fields that are not initialized (null) are built
- * using the field factory. All non-null fields for which a property id can
- * be determined are bound to the property id.
+ * {@link Field} and that can be mapped to a property id. Property ids are
+ * searched in the following order: @{@link PropertyId} annotations, exact
+ * field name matches and the case-insensitive matching that ignores
+ * underscores. Fields that are not initialized (null) are built using the
+ * field factory. All non-null fields for which a property id can be
+ * determined are bound to the property id.
* </p>
* <p>
* For example:
@@ -777,11 +778,12 @@ public class FieldGroup implements Serializable {
* member fields that have not been initialized.
* <p>
* This method processes all (Java) member fields whose type extends
- * {@link Field} and that can be mapped to a property id. Property id
- * mapping is done based on the field name or on a @{@link PropertyId}
- * annotation on the field. Fields that are not initialized (null) are built
- * using the field factory is buildFields is true. All non-null fields for
- * which a property id can be determined are bound to the property id.
+ * {@link Field} and that can be mapped to a property id. Property ids are
+ * searched in the following order: @{@link PropertyId} annotations, exact
+ * field name matches and the case-insensitive matching that ignores
+ * underscores. Fields that are not initialized (null) are built using the
+ * field factory is buildFields is true. All non-null fields for which a
+ * property id can be determined are bound to the property id.
* </p>
*
* @param objectWithMemberFields
@@ -812,7 +814,16 @@ public class FieldGroup implements Serializable {
// @PropertyId(propertyId) always overrides property id
propertyId = propertyIdAnnotation.value();
} else {
- propertyId = memberField.getName();
+ try {
+ propertyId = findPropertyId(memberField);
+ } catch (SearchException e) {
+ // Property id was not found, skip this field
+ continue;
+ }
+ if (propertyId == null) {
+ // Property id was not found, skip this field
+ continue;
+ }
}
// Ensure that the property id exists
@@ -873,6 +884,54 @@ public class FieldGroup implements Serializable {
}
}
+ /**
+ * Searches for a property id from the current itemDataSource that matches
+ * the given memberField.
+ * <p>
+ * If perfect match is not found, uses a case insensitive search that also
+ * ignores underscores. Returns null if no match is found. Throws a
+ * SearchException if no item data source has been set.
+ * </p>
+ * <p>
+ * The propertyId search logic used by
+ * {@link #buildAndBindMemberFields(Object, boolean)
+ * buildAndBindMemberFields} can easily be customized by overriding this
+ * method. No other changes are needed.
+ * </p>
+ *
+ * @param memberField
+ * The field an object id is searched for
+ * @return
+ */
+ protected Object findPropertyId(java.lang.reflect.Field memberField) {
+ String fieldName = memberField.getName();
+ if (getItemDataSource() == null) {
+ throw new SearchException(
+ "Property id type for field '"
+ + fieldName
+ + "' could not be determined. No item data source has been set.");
+ }
+ Item dataSource = getItemDataSource();
+ if (dataSource.getItemProperty(fieldName) != null) {
+ return fieldName;
+ } else {
+ String minifiedFieldName = minifyFieldName(fieldName);
+ for (Object itemPropertyId : dataSource.getItemPropertyIds()) {
+ if (itemPropertyId instanceof String) {
+ String itemPropertyName = (String) itemPropertyId;
+ if (minifiedFieldName.equals(minifyFieldName(itemPropertyName))) {
+ return itemPropertyName;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ protected static String minifyFieldName(String fieldName) {
+ return fieldName.toLowerCase().replace("_", "");
+ }
+
public static class CommitException extends Exception {
public CommitException() {
@@ -909,6 +968,18 @@ public class FieldGroup implements Serializable {
}
+ public static class SearchException extends RuntimeException {
+
+ public SearchException(String message) {
+ super(message);
+ }
+
+ public SearchException(String message, Throwable t) {
+ super(message, t);
+ }
+
+ }
+
/**
* Builds a field and binds it to the given property id using the field
* binder.
diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java
index c1c18901b4..cd7279e601 100644
--- a/server/src/com/vaadin/server/AbstractCommunicationManager.java
+++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java
@@ -1780,11 +1780,18 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (connectorTracker.getConnector(connectorId) == null
&& !connectorId
.equals(ApplicationConstants.DRAG_AND_DROP_CONNECTOR_ID)) {
- getLogger().log(
- Level.WARNING,
- "RPC call to " + interfaceName + "." + methodName
- + " received for connector " + connectorId
- + " but no such connector could be found");
+ getLogger()
+ .log(Level.WARNING,
+ "RPC call to "
+ + interfaceName
+ + "."
+ + methodName
+ + " received for connector "
+ + connectorId
+ + " but no such connector could be found. Resynchronizing client.");
+ // This is likely an out of sync issue (client tries to update a
+ // connector which is not present). Force resync.
+ connectorTracker.markAllConnectorsDirty();
return null;
}
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index 85c40e0d39..06060dbf91 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -122,7 +122,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
*/
@Override
public String getId() {
- return getState().id;
+ return getState(false).id;
}
/**
@@ -233,7 +233,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
*/
@Override
public String getCaption() {
- return getState().caption;
+ return getState(false).caption;
}
/**
@@ -363,7 +363,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
* interface.
*/
public boolean isImmediate() {
- return getState().immediate;
+ return getState(false).immediate;
}
/**
@@ -423,7 +423,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
*/
@Override
public String getDescription() {
- return getState().description;
+ return getState(false).description;
}
/**
@@ -532,7 +532,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
*/
@Override
public boolean isReadOnly() {
- return getState().readOnly;
+ return getState(false).readOnly;
}
/*
@@ -622,6 +622,11 @@ public abstract class AbstractComponent extends AbstractClientConnector
}
@Override
+ protected AbstractComponentState getState(boolean markAsDirty) {
+ return (AbstractComponentState) super.getState(markAsDirty);
+ }
+
+ @Override
public void beforeClientResponse(boolean initial) {
super.beforeClientResponse(initial);
// TODO This logic should be on the client side and the state should