Skip to content

Commit

Permalink
[Blazebit#705] Properly copy and reset dirty state when converting en…
Browse files Browse the repository at this point in the history
…tity view types
  • Loading branch information
beikov committed Dec 19, 2018
1 parent 55ab86f commit 16b1c7c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.blazebit.persistence.view.impl.metamodel.AbstractAttribute;
import com.blazebit.persistence.view.impl.metamodel.AbstractMethodAttribute;
import com.blazebit.persistence.view.impl.proxy.ConvertReflectionInstantiator;
import com.blazebit.persistence.view.impl.proxy.DirtyStateTrackable;
import com.blazebit.persistence.view.impl.proxy.DirtyTracker;
import com.blazebit.persistence.view.impl.proxy.ObjectInstantiator;
import com.blazebit.persistence.view.impl.proxy.ProxyFactory;
Expand Down Expand Up @@ -53,6 +54,7 @@
public class ViewMapper<S, T> {

private final int[] dirtyMapping;
private final boolean copyInitialState;
private final AttributeAccessor[] sourceAccessors;
private final ObjectInstantiator<T> objectInstantiator;

Expand Down Expand Up @@ -83,19 +85,17 @@ public ViewMapper(ManagedViewType<S> sourceType, ManagedViewType<T> targetType,
if (targetAttribute != idAttribute) {
parameterTypes[i] = targetAttribute.getConvertedJavaType();
sourceAccessors[i] = createAccessor(sourceType, targetType, ignoreMissing, markNew, entityViewManager, proxyFactory, targetAttribute);
if (!markNew) {
// Extract a mapping from target dirty state index to the source
int dirtyStateIndex = ((AbstractMethodAttribute<?, ?>) targetAttribute).getDirtyStateIndex();
if (dirtyStateIndex != -1) {
MethodAttribute<? super S, ?> sourceAttribute = sourceType.getAttribute(targetAttribute.getName());
if (sourceAttribute != null) {
int sourceIndex = ((AbstractMethodAttribute<?, ?>) sourceAttribute).getDirtyStateIndex();
if (sourceIndex != -1) {
for (int j = dirtyMapping.size(); j <= dirtyStateIndex; j++) {
dirtyMapping.add(-1);
}
dirtyMapping.set(dirtyStateIndex, sourceIndex);
// Extract a mapping from target dirty state index to the source
int dirtyStateIndex = ((AbstractMethodAttribute<?, ?>) targetAttribute).getDirtyStateIndex();
if (dirtyStateIndex != -1) {
MethodAttribute<? super S, ?> sourceAttribute = sourceType.getAttribute(targetAttribute.getName());
if (sourceAttribute != null) {
int sourceIndex = ((AbstractMethodAttribute<?, ?>) sourceAttribute).getDirtyStateIndex();
if (sourceIndex != -1) {
for (int j = dirtyMapping.size(); j <= dirtyStateIndex; j++) {
dirtyMapping.add(-1);
}
dirtyMapping.set(dirtyStateIndex, sourceIndex);
}
}
}
Expand All @@ -113,6 +113,7 @@ public ViewMapper(ManagedViewType<S> sourceType, ManagedViewType<T> targetType,
this.dirtyMapping = dirtyMappingArray;
}

this.copyInitialState = !markNew;
this.sourceAccessors = sourceAccessors;
this.objectInstantiator = new ConvertReflectionInstantiator<>(proxyFactory, targetType, parameterTypes, markNew, entityViewManager);
}
Expand Down Expand Up @@ -190,13 +191,39 @@ public T map(S source) {
}
}
T result = objectInstantiator.newInstance(tuple);
// TODO: copy initial state, on create new, mark everything as dirty
if (dirtyMapping != null && source instanceof DirtyTracker) {
DirtyTracker oldDirtyTracker = (DirtyTracker) source;
DirtyTracker dirtyTracker = (DirtyTracker) result;
for (int i = 0; i < dirtyMapping.length; i++) {
if (oldDirtyTracker.$$_isDirty(dirtyMapping[i])) {
dirtyTracker.$$_markDirty(i);
if (copyInitialState) {
if (oldDirtyTracker instanceof DirtyStateTrackable && dirtyTracker instanceof DirtyStateTrackable) {
Object[] oldInitial = ((DirtyStateTrackable) oldDirtyTracker).$$_getInitialState();
Object[] newInitial = ((DirtyStateTrackable) dirtyTracker).$$_getInitialState();
for (int i = 0; i < dirtyMapping.length; i++) {
int dirtyStateIndex = dirtyMapping[i];
if (oldDirtyTracker.$$_isDirty(dirtyStateIndex)) {
newInitial[dirtyStateIndex] = oldInitial[dirtyStateIndex];
dirtyTracker.$$_markDirty(i);
}
}
} else {
for (int i = 0; i < dirtyMapping.length; i++) {
if (oldDirtyTracker.$$_isDirty(dirtyMapping[i])) {
dirtyTracker.$$_markDirty(i);
}
}
}
} else {
// Reset the initial state i.e. mark it as new
if (dirtyTracker instanceof DirtyStateTrackable) {
Object[] initialState = ((DirtyStateTrackable) dirtyTracker).$$_getInitialState();
for (int i = 0; i < initialState.length; i++) {
initialState[i] = null;
}
}
for (int i = 0; i < dirtyMapping.length; i++) {
if (oldDirtyTracker.$$_isDirty(dirtyMapping[i])) {
dirtyTracker.$$_markDirty(i);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@
import com.blazebit.persistence.testsuite.entity.Document;
import com.blazebit.persistence.testsuite.entity.Person;
import com.blazebit.persistence.testsuite.tx.TxVoidWork;
import com.blazebit.persistence.view.ConvertOption;
import com.blazebit.persistence.view.EntityViewManager;
import com.blazebit.persistence.view.EntityViewSetting;
import com.blazebit.persistence.view.EntityViews;
import com.blazebit.persistence.view.change.ChangeModel;
import com.blazebit.persistence.view.spi.EntityViewConfiguration;
import com.blazebit.persistence.view.testsuite.AbstractEntityViewTest;
import com.blazebit.persistence.view.testsuite.convert.view.model.DocumentCloneUpdateView;
import com.blazebit.persistence.view.testsuite.convert.view.model.DocumentCloneView;
import com.blazebit.persistence.view.testsuite.convert.view.model.DocumentIdView;
import com.blazebit.persistence.view.testsuite.convert.view.model.PersonView;
Expand All @@ -36,7 +39,7 @@

import javax.persistence.EntityManager;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;

/**
*
Expand All @@ -54,6 +57,7 @@ public void initEvm() {
EntityViewConfiguration cfg = EntityViews.createDefaultConfiguration();
cfg.addEntityView(DocumentIdView.class);
cfg.addEntityView(DocumentCloneView.class);
cfg.addEntityView(DocumentCloneUpdateView.class);
cfg.addEntityView(SimplePersonView.class);
cfg.addEntityView(PersonView.class);
evm = cfg.createEntityViewManager(cbf);
Expand Down Expand Up @@ -124,4 +128,32 @@ public void testConvertSubset() {
assertEquals(documentView.getOwner(), idView.getOwner());
assertEquals(documentView.getOwner().getName(), idView.getOwner().getName());
}

@Test
public void testConvertDirty() {
CriteriaBuilder<Document> criteria = cbf.create(em, Document.class);
DocumentCloneUpdateView documentView = evm.applySetting(EntityViewSetting.create(DocumentCloneUpdateView.class), criteria)
.getSingleResult();

documentView.setName("abc");
DocumentCloneUpdateView secondView = evm.convert(documentView, DocumentCloneUpdateView.class);

ChangeModel<Object> nameChange = evm.getChangeModel(secondView).get("name");
assertTrue(nameChange.isDirty());
assertEquals("doc1", nameChange.getInitialState());
}

@Test
public void testConvertDirtyToNew() {
CriteriaBuilder<Document> criteria = cbf.create(em, Document.class);
DocumentCloneUpdateView documentView = evm.applySetting(EntityViewSetting.create(DocumentCloneUpdateView.class), criteria)
.getSingleResult();

documentView.setName("abc");
DocumentCloneUpdateView secondView = evm.convert(documentView, DocumentCloneUpdateView.class, ConvertOption.CREATE_NEW);

ChangeModel<Object> nameChange = evm.getChangeModel(secondView).get("name");
assertTrue(nameChange.isDirty());
assertNull(nameChange.getInitialState());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2014 - 2018 Blazebit.
*
* 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.blazebit.persistence.view.testsuite.convert.view.model;

import com.blazebit.persistence.testsuite.entity.Document;
import com.blazebit.persistence.testsuite.entity.Person;
import com.blazebit.persistence.view.CreatableEntityView;
import com.blazebit.persistence.view.EntityView;
import com.blazebit.persistence.view.IdMapping;
import com.blazebit.persistence.view.UpdatableEntityView;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
*
* @author Christian Beikov
* @since 1.4.0
*/
@EntityView(Document.class)
@UpdatableEntityView
@CreatableEntityView(validatePersistability = false)
public interface DocumentCloneUpdateView extends DocumentCloneView {

public void setName(String name);

public void setAge(long age);

public void setOwner(PersonView owner);

public void setPeople(List<PersonView> people);

public void setPartners(Set<PersonView> partners);

public void setContacts(Map<Integer, Person> contacts);
}

0 comments on commit 16b1c7c

Please sign in to comment.