Last active
April 28, 2016 12:37
-
-
Save simonbasle/592b86641bffb2c95943a46c3da57dfa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2015 Couchbase Inc., the original author or authors. | |
* | |
* 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.couchbase.client.spring.cache; | |
import com.couchbase.client.java.Bucket; | |
import com.couchbase.client.java.document.SerializableDocument; | |
import com.couchbase.client.spring.cache.serialization.model.Foo; | |
import com.couchbase.client.spring.cache.serialization.model.Other; | |
import org.junit.Before; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.test.context.ContextConfiguration; | |
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | |
import rx.Observable; | |
import rx.functions.Func1; | |
import static com.couchbase.client.spring.cache.serialization.model.SharedCache.SharedCache; | |
import static org.hamcrest.CoreMatchers.is; | |
import static org.junit.Assert.assertNotNull; | |
import static org.junit.Assert.assertThat; | |
import java.io.FileInputStream; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
@RunWith(SpringJUnit4ClassRunner.class) | |
@ContextConfiguration(classes = TestConfiguration.class) | |
public class DeepSerializationTest { | |
private final String cacheName = "test"; | |
private int DEEP_LEVEL = 4; | |
@Autowired | |
private Bucket client; | |
private CouchbaseCache cache; | |
@Before | |
public void setUp() { | |
cache = new CouchbaseCache(cacheName, client); | |
SharedCache.setCache(cache); | |
} | |
@Test | |
public void testJavaSerialization() throws IOException, ClassNotFoundException { | |
Foo f = getFooStructure(); | |
FileOutputStream fos = new FileOutputStream("temp.out"); | |
ObjectOutputStream oos = new ObjectOutputStream(fos); | |
oos.writeObject(f); | |
oos.flush(); | |
oos.close(); | |
FileInputStream fis = new FileInputStream("temp.out"); | |
ObjectInputStream oin = new ObjectInputStream(fis); | |
Foo storedFoo = (Foo) oin.readObject(); | |
System.out.println(storedFoo); | |
} | |
/** | |
* The following test will fail to deserialize when DEEP_LEVEL is larger than number of thread pool | |
*/ | |
@Test | |
public void shouldDeserializeComplexObject() throws InterruptedException { | |
// Given | |
final Foo expected = getFooStructure(); | |
// When | |
final Foo retrieved = getFoo(expected.getId()).toBlocking().singleOrDefault(null); | |
// Then | |
assertThat(retrieved, is(expected)); | |
} | |
static final Func1<SerializableDocument, Foo> SERIAL_TO_FOO = new Func1<SerializableDocument, Foo>() { | |
@Override | |
public Foo call(SerializableDocument sd) { | |
return (Foo) sd.content(); | |
} | |
}; | |
static final Func1<SerializableDocument, Other> SERIAL_TO_OTHER = new Func1<SerializableDocument, Other>() { | |
@Override | |
public Other call(SerializableDocument sd) { | |
return (Other) sd.content(); | |
} | |
}; | |
private Observable<Foo> getFoo(String fooId) { | |
return client.async() | |
.get(cache.getDocumentId(fooId), SerializableDocument.class) | |
.map(SERIAL_TO_FOO) | |
.flatMap(new Func1<Foo, Observable<Foo>>() { | |
@Override | |
public Observable<Foo> call(final Foo foo) { | |
if (foo.getOtherId() != null && foo.getOther() == null) { | |
return getOther(foo.getOtherId()).map(new Func1<Other, Foo>() { | |
@Override | |
public Foo call(Other other) { | |
foo.setOther(other); | |
return foo; | |
} | |
}); | |
} | |
return Observable.just(foo); | |
} | |
}); | |
} | |
private Observable<Other> getOther(String otherId) { | |
return client.async() | |
.get(cache.getDocumentId(otherId), SerializableDocument.class) | |
.map(SERIAL_TO_OTHER) | |
.flatMap(new Func1<Other, Observable<Other>>() { | |
@Override | |
public Observable<Other> call(final Other other) { | |
if (other.getFooId() != null && other.getFoo() == null) { | |
return getFoo(other.getFooId()).map(new Func1<Foo, Other>() { | |
@Override | |
public Other call(Foo foo) { | |
other.setFoo(foo); | |
return other; | |
} | |
}); | |
} | |
return Observable.just(other); | |
} | |
}); | |
} | |
/** | |
* Build Foo->Other object composition based on DEEP_LEVEL. For a level 3 you should see: | |
* Level 0 Level 1 Level 2 Level 3 | |
* ----^---- ----^---- ----^---- ----^---- | |
* Foo->Other | |
* |-> Foo->Other | |
* |-> Foo->Other | |
* |-> Foo->Other | |
*/ | |
private Foo getFooStructure() { | |
final Foo root = createFoo(0); | |
Foo current = root; | |
for (int id = 1; id <= DEEP_LEVEL; id++) { | |
current.getOther().setFoo(createFoo(id)); | |
cache.put(current.getOther().getId(), current.getOther()); | |
current = current.getOther().getFoo(); | |
} | |
// cache.put(root.getId(), root); | |
return root; | |
} | |
private Foo createFoo(final int id) { | |
final Other other = new Other(); | |
other.setId("Other" + id); | |
other.setDescription("Other" + id + " description"); | |
cache.put(other.getId(), other); | |
final Foo foo = new Foo(); | |
foo.setId("Foo" + id); | |
foo.setDescription("Foo" + id + " description"); | |
foo.setOther(other); | |
cache.put(foo.getId(), foo); | |
return foo; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.couchbase.client.spring.cache.serialization.model; | |
import java.io.Serializable; | |
public class Foo implements Serializable { | |
private String id; | |
private String description; | |
private String otherId; | |
private transient Other other; | |
public String getId() { | |
return id; | |
} | |
public void setId(final String id) { | |
this.id = id; | |
} | |
public String getDescription() { | |
return description; | |
} | |
public void setDescription(final String description) { | |
this.description = description; | |
} | |
public String getOtherId() { | |
return otherId; | |
} | |
public void setOtherId(final String otherId) { | |
this.otherId = otherId; | |
} | |
public Other getOther() { | |
return other; | |
} | |
public void setOther(final Other other) { | |
this.otherId = other.getId(); | |
this.other = other; | |
} | |
@Override | |
public String toString() { | |
return "Foo{" + | |
"id='" + id + '\'' + | |
", description='" + description + '\'' + | |
", otherId='" + otherId + '\'' + | |
", other=" + other + | |
'}'; | |
} | |
@Override | |
public boolean equals(final Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
final Foo foo = (Foo) o; | |
if (id != null ? !id.equals(foo.id) : foo.id != null) return false; | |
if (description != null ? !description.equals(foo.description) : foo.description != null) return false; | |
if (otherId != null ? !otherId.equals(foo.otherId) : foo.otherId != null) return false; | |
return other != null ? other.equals(foo.other) : foo.other == null; | |
} | |
@Override | |
public int hashCode() { | |
int result = id != null ? id.hashCode() : 0; | |
result = 31 * result + (description != null ? description.hashCode() : 0); | |
result = 31 * result + (otherId != null ? otherId.hashCode() : 0); | |
result = 31 * result + (other != null ? other.hashCode() : 0); | |
return result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.couchbase.client.spring.cache.serialization.model; | |
import java.io.Serializable; | |
public class Other implements Serializable { | |
private String id; | |
private String description; | |
private String fooId; | |
private transient Foo foo; | |
public String getId() { | |
return id; | |
} | |
public void setId(final String id) { | |
this.id = id; | |
} | |
public String getDescription() { | |
return description; | |
} | |
public void setDescription(final String description) { | |
this.description = description; | |
} | |
public String getFooId() { | |
return fooId; | |
} | |
public void setFooId(final String fooId) { | |
this.fooId = fooId; | |
} | |
public Foo getFoo() { | |
return foo; | |
} | |
public void setFoo(final Foo foo) { | |
this.fooId = foo.getId(); | |
this.foo = foo; | |
} | |
@Override | |
public boolean equals(final Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
final Other other = (Other) o; | |
if (id != null ? !id.equals(other.id) : other.id != null) return false; | |
if (description != null ? !description.equals(other.description) : other.description != null) return false; | |
if (fooId != null ? !fooId.equals(other.fooId) : other.fooId != null) return false; | |
return foo != null ? foo.equals(other.foo) : other.foo == null; | |
} | |
@Override | |
public int hashCode() { | |
int result = id != null ? id.hashCode() : 0; | |
result = 31 * result + (description != null ? description.hashCode() : 0); | |
result = 31 * result + (fooId != null ? fooId.hashCode() : 0); | |
result = 31 * result + (foo != null ? foo.hashCode() : 0); | |
return result; | |
} | |
@Override | |
public String toString() { | |
return "Other{" + | |
"id='" + id + '\'' + | |
", description='" + description + '\'' + | |
", fooId='" + fooId + '\'' + | |
", foo=" + foo + | |
'}'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment