Skip to content

Commit 16dc4b5

Browse files
christophstroblThomas Darimont
authored and
Thomas Darimont
committed
DATAKV-99 - Add KeyValueIterator.
We now offer the possibility to iterate through available key/value pairs via a KeyValueIterator. The default implementation for java.util.Map based Adapters is a ForwardingKeyValueIterator delegating to the underlying entrySet iterator. Original pull request: #7.
1 parent aa3204e commit 16dc4b5

File tree

8 files changed

+372
-1
lines changed

8 files changed

+372
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.core;
17+
18+
import java.util.Map;
19+
20+
/**
21+
* @author Christoph Strobl
22+
* @param <K>
23+
* @param <V>
24+
*/
25+
public interface Entry<K, V> extends Map.Entry<K, V> {
26+
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.core;
17+
18+
import java.io.IOException;
19+
import java.util.Iterator;
20+
import java.util.Map;
21+
22+
/**
23+
* @author Christoph Strobl
24+
* @param <K>
25+
* @param <V>
26+
*/
27+
public class ForwardingKeyValueIterator<K, V> implements KeyValueIterator<K, V> {
28+
29+
private final Iterator<? extends Map.Entry<K, V>> delegate;
30+
31+
public ForwardingKeyValueIterator(Iterator<? extends java.util.Map.Entry<K, V>> delegate) {
32+
this.delegate = delegate;
33+
}
34+
35+
@Override
36+
public boolean hasNext() {
37+
return delegate.hasNext();
38+
}
39+
40+
@Override
41+
public Entry<K, V> next() {
42+
return new ForwardingEntry(delegate.next());
43+
}
44+
45+
@Override
46+
public void close() throws IOException {
47+
48+
}
49+
50+
class ForwardingEntry implements Entry<K, V> {
51+
52+
private final Map.Entry<K, V> entry;
53+
54+
public ForwardingEntry(Map.Entry<K, V> entry) {
55+
this.entry = entry;
56+
}
57+
58+
@Override
59+
public K getKey() {
60+
return entry.getKey();
61+
}
62+
63+
@Override
64+
public V getValue() {
65+
return entry.getValue();
66+
}
67+
68+
@Override
69+
public V setValue(V value) {
70+
return entry.setValue(value);
71+
}
72+
73+
@Override
74+
public String toString() {
75+
return entry != null ? entry.toString() : "null";
76+
}
77+
78+
}
79+
}

src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java

+9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* {@link KeyValueAdapter} unifies access and shields the underlying key/value specific implementation.
2626
*
2727
* @author Christoph Strobl
28+
* @author Thomas Darimont
2829
*/
2930
public interface KeyValueAdapter extends DisposableBean {
3031

@@ -72,6 +73,14 @@ public interface KeyValueAdapter extends DisposableBean {
7273
*/
7374
Collection<?> getAllOf(Serializable keyspace);
7475

76+
/**
77+
* Returns a {@link KeyValueIterator} that iterates over all entries.
78+
*
79+
* @param keyspace
80+
* @return
81+
*/
82+
KeyValueIterator<? extends Serializable, ?> entries(Serializable keyspace);
83+
7584
/**
7685
* Remove all objects of given type.
7786
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.core;
17+
18+
import java.io.Closeable;
19+
import java.util.Iterator;
20+
21+
/**
22+
* @author Christoph Strobl
23+
* @param <K>
24+
* @param <V>
25+
*/
26+
public interface KeyValueIterator<K, V> extends Iterator<Entry<K, V>>, Closeable {
27+
28+
}

src/main/java/org/springframework/data/map/MapKeyValueAdapter.java

+12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
import org.springframework.core.CollectionFactory;
2424
import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter;
25+
import org.springframework.data.keyvalue.core.ForwardingKeyValueIterator;
2526
import org.springframework.data.keyvalue.core.KeyValueAdapter;
27+
import org.springframework.data.keyvalue.core.KeyValueIterator;
2628
import org.springframework.util.Assert;
2729
import org.springframework.util.ClassUtils;
2830

@@ -133,6 +135,15 @@ public Collection<?> getAllOf(Serializable keyspace) {
133135
return getKeySpaceMap(keyspace).values();
134136
}
135137

138+
/*
139+
* (non-Javadoc)
140+
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#entries(java.io.Serializable)
141+
*/
142+
@Override
143+
public KeyValueIterator<Serializable, ?> entries(Serializable keyspace) {
144+
return new ForwardingKeyValueIterator<Serializable, Object>(getKeySpaceMap(keyspace).entrySet().iterator());
145+
}
146+
136147
/*
137148
* (non-Javadoc)
138149
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#deleteAllOf(java.io.Serializable)
@@ -194,4 +205,5 @@ protected Map<Serializable, Object> getKeySpaceMap(Serializable keyspace) {
194205
private void addMapForKeySpace(Serializable keyspace) {
195206
store.put(keyspace, CollectionFactory.<Serializable, Object> createMap(keySpaceMapType, 1000));
196207
}
208+
197209
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.core;
17+
18+
import static org.hamcrest.core.Is.*;
19+
import static org.hamcrest.core.IsNull.*;
20+
import static org.junit.Assert.*;
21+
import static org.mockito.Mockito.*;
22+
23+
import java.io.IOException;
24+
import java.util.Iterator;
25+
import java.util.Map;
26+
import java.util.NoSuchElementException;
27+
28+
import org.junit.Test;
29+
import org.junit.runner.RunWith;
30+
import org.mockito.Mock;
31+
import org.mockito.runners.MockitoJUnitRunner;
32+
33+
/**
34+
* @author Christoph Strobl
35+
*/
36+
@RunWith(MockitoJUnitRunner.class)
37+
public class ForwardingIteratorUnitTests<K, V> {
38+
39+
@Mock Iterator<Map.Entry<K, V>> iteratorMock;
40+
41+
/**
42+
* @see DATAKV-99
43+
*/
44+
@Test
45+
public void hasNextShoudDelegateToWrappedIterator() {
46+
47+
when(iteratorMock.hasNext()).thenReturn(true);
48+
49+
assertThat(new ForwardingKeyValueIterator<K, V>(iteratorMock).hasNext(), is(true));
50+
51+
verify(iteratorMock, times(1)).hasNext();
52+
}
53+
54+
/**
55+
* @see DATAKV-99
56+
*/
57+
@Test
58+
public void nextShoudDelegateToWrappedIterator() {
59+
60+
when(iteratorMock.next()).thenReturn((Map.Entry<K, V>) mock(Map.Entry.class));
61+
62+
assertThat(new ForwardingKeyValueIterator<K, V>(iteratorMock).next(), notNullValue());
63+
64+
verify(iteratorMock, times(1)).next();
65+
}
66+
67+
/**
68+
* @see DATAKV-99
69+
*/
70+
@Test(expected = NoSuchElementException.class)
71+
public void nextShoudThrowErrorWhenWrappedIteratorHasNoMoreElements() {
72+
73+
when(iteratorMock.next()).thenThrow(new NoSuchElementException());
74+
75+
new ForwardingKeyValueIterator<K, V>(iteratorMock).next();
76+
}
77+
78+
/**
79+
* @see DATAKV-99
80+
*/
81+
@Test
82+
public void closeShouldDoNothing() throws IOException {
83+
84+
new ForwardingKeyValueIterator<K, V>(iteratorMock).close();
85+
86+
verifyZeroInteractions(iteratorMock);
87+
}
88+
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.keyvalue.test.util;
17+
18+
import org.hamcrest.CustomMatcher;
19+
import org.hamcrest.core.IsEqual;
20+
import org.springframework.data.keyvalue.core.Entry;
21+
22+
/**
23+
* @author Christoph Strobl
24+
*/
25+
public class IsEntry extends CustomMatcher<Entry<?, ?>> {
26+
27+
private final Entry<?, ?> expected;
28+
29+
private IsEntry(Entry<?, ?> entry) {
30+
super(String.format("an entry %s=%s.", entry != null ? entry.getKey() : "null", entry != null ? entry.getValue()
31+
: "null"));
32+
this.expected = entry;
33+
}
34+
35+
@Override
36+
public boolean matches(Object item) {
37+
38+
if (item == null && expected == null) {
39+
return true;
40+
}
41+
42+
if (!(item instanceof Entry)) {
43+
return false;
44+
}
45+
46+
Entry<?, ?> actual = (Entry<?, ?>) item;
47+
48+
return new IsEqual<Object>(expected.getKey()).matches(actual.getKey())
49+
&& new IsEqual<Object>(expected.getValue()).matches(actual.getValue());
50+
}
51+
52+
public static IsEntry isEntry(Object key, Object value) {
53+
return isEntry(new EntryImpl(key, value));
54+
}
55+
56+
public static IsEntry isEntry(Entry<?, ?> entry) {
57+
return new IsEntry(entry);
58+
}
59+
60+
private static class EntryImpl implements Entry<Object, Object> {
61+
62+
private final Object key;
63+
private final Object value;
64+
65+
private EntryImpl(Object key, Object value) {
66+
this.key = key;
67+
this.value = value;
68+
}
69+
70+
@Override
71+
public Object getKey() {
72+
return key;
73+
}
74+
75+
@Override
76+
public Object getValue() {
77+
return value;
78+
}
79+
80+
@Override
81+
public Object setValue(Object value) {
82+
throw new UnsupportedOperationException();
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)