/** * Apply changes to the underlying adapter (possibly returning a new adapter). * * @return adapter, which may be different from the original (if a {@link * ViewModelFacet#isCloneable(Object) cloneable} view model, for example. */ public ObjectAdapter apply() { ObjectAdapter adapter = getObjectAdapterMemento().getObjectAdapter(ConcurrencyChecking.CHECK); for (final ScalarModel scalarModel : propertyScalarModels.values()) { final OneToOneAssociation property = scalarModel.getPropertyMemento().getProperty(); // // previously there was a guard here to only apply changes provided: // // property.containsDoOpFacet(NotPersistedFacet.class) == null // // however, that logic is wrong; although a property may not be directly // persisted so far as JDO is concerned, it may be indirectly persisted // as the result of business logic in the setter. // // for example, see ExampleTaggableEntity (in isisaddons-module-tags). // // // on the other hand, we mustn't attempt to apply changes for disabled properties... // even if the property is persisted (it might be written to by an action), it is never // updated by // an edit. // // Fundamentally, then, any non-disabled property (whether persisted or not) should be updated // in the // Isis runtime. // if (property.containsDoOpFacet(DisabledFacet.class)) { // skip, as per comments above continue; } final ObjectAdapter associate = scalarModel.getObject(); property.set(adapter, associate, InteractionInitiatedBy.USER); } final ViewModelFacet recreatableObjectFacet = adapter.getSpecification().getFacet(ViewModelFacet.class); if (recreatableObjectFacet != null) { final Object viewModel = adapter.getObject(); final boolean cloneable = recreatableObjectFacet.isCloneable(viewModel); if (cloneable) { final Object newViewModel = recreatableObjectFacet.clone(viewModel); adapter = getAdapterManager().adapterFor(newViewModel); } } getObjectAdapterMemento().setAdapter(adapter); toViewMode(); return adapter; }