MapKeyValueAdapter.java
/*
* Copyright 2014-2025 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
*
* https://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 org.springframework.data.map;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.jspecify.annotations.Nullable;
import org.springframework.data.keyvalue.core.AbstractKeyValueAdapter;
import org.springframework.data.keyvalue.core.ForwardingCloseableIterator;
import org.springframework.data.keyvalue.core.KeyValueAdapter;
import org.springframework.data.keyvalue.core.PredicateQueryEngine;
import org.springframework.data.keyvalue.core.QueryEngine;
import org.springframework.data.keyvalue.core.SortAccessor;
import org.springframework.data.util.CloseableIterator;
import org.springframework.util.Assert;
/**
* {@link KeyValueAdapter} implementation for {@link Map}.
*
* @author Christoph Strobl
* @author Derek Cochran
* @author Marcel Overdijk
*/
public class MapKeyValueAdapter extends AbstractKeyValueAdapter {
private final KeySpaceStore store;
/**
* Create new {@link MapKeyValueAdapter} using {@link ConcurrentHashMap} as backing store type.
*/
public MapKeyValueAdapter() {
this(MapKeySpaceStore.create());
}
/**
* Create new {@link MapKeyValueAdapter} using the given query engine.
*
* @param engine the query engine.
* @since 2.4
*/
public MapKeyValueAdapter(QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
this(MapKeySpaceStore.create(), engine);
}
/**
* Creates a new {@link MapKeyValueAdapter} using the given {@link Map} as backing store.
*
* @param mapType must not be {@literal null}.
*/
@SuppressWarnings("rawtypes")
public MapKeyValueAdapter(Class<? extends Map> mapType) {
this(MapKeySpaceStore.of(mapType));
}
/**
* Creates a new {@link MapKeyValueAdapter} using the given {@link Map} as backing store.
*
* @param mapType must not be {@literal null}.
* @param sortAccessor accessor granting access to sorting implementation
* @since 3.1.10
*/
@SuppressWarnings("rawtypes")
public MapKeyValueAdapter(Class<? extends Map> mapType, SortAccessor<Comparator<?>> sortAccessor) {
this(MapKeySpaceStore.of(mapType), new PredicateQueryEngine(sortAccessor));
}
/**
* Creates a new {@link MapKeyValueAdapter} using the given {@link Map} as backing store and query engine.
*
* @param mapType must not be {@literal null}.
* @param engine the query engine.
* @since 2.4
*/
@SuppressWarnings("rawtypes")
public MapKeyValueAdapter(Class<? extends Map> mapType, QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
this(MapKeySpaceStore.of(mapType), engine);
}
/**
* Create new instance of {@link MapKeyValueAdapter} using given dataStore for persistence.
*
* @param store must not be {@literal null}.
*/
public MapKeyValueAdapter(Map<String, Map<Object, Object>> store) {
this(MapKeySpaceStore.of(store));
}
/**
* Create new instance of {@link MapKeyValueAdapter} using given dataStore for persistence and query engine.
*
* @param store must not be {@literal null}.
* @param engine the query engine.
* @since 2.4
*/
public MapKeyValueAdapter(Map<String, Map<Object, Object>> store, QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
this(MapKeySpaceStore.of(store), engine);
}
/**
* Create new instance of {@link MapKeyValueAdapter} using given dataStore for persistence.
*
* @param store must not be {@literal null}.
*/
public MapKeyValueAdapter(KeySpaceStore store) {
this(store, new PredicateQueryEngine());
}
/**
* Creates a new {@link MapKeyValueAdapter} with the given store and type to be used when creating key spaces and
* query engine.
*
* @param store must not be {@literal null}.
* @param engine the query engine.
*/
public MapKeyValueAdapter(KeySpaceStore store, @Nullable QueryEngine<? extends KeyValueAdapter, ?, ?> engine) {
super(engine);
Assert.notNull(store, "KeyspaceStore must not be null");
this.store = store;
}
@Override
public @Nullable Object put(Object id, Object item, String keyspace) {
Assert.notNull(id, "Cannot add item with null id");
Assert.notNull(keyspace, "Cannot add item for null collection");
return getKeySpaceMap(keyspace).put(id, item);
}
@Override
public boolean contains(Object id, String keyspace) {
return get(id, keyspace) != null;
}
@Override
public long count(String keyspace) {
return getKeySpaceMap(keyspace).size();
}
@Override
public @Nullable Object get(Object id, String keyspace) {
Assert.notNull(id, "Cannot get item with null id");
return getKeySpaceMap(keyspace).get(id);
}
@Override
public @Nullable Object delete(Object id, String keyspace) {
Assert.notNull(id, "Cannot delete item with null id");
return getKeySpaceMap(keyspace).remove(id);
}
@Override
public Collection<Object> getAllOf(String keyspace) {
return getKeySpaceMap(keyspace).values();
}
@Override
public CloseableIterator<Entry<Object, Object>> entries(String keyspace) {
return new ForwardingCloseableIterator<>(getKeySpaceMap(keyspace).entrySet().iterator());
}
@Override
public void deleteAllOf(String keyspace) {
getKeySpaceMap(keyspace).clear();
}
@Override
public void clear() {
store.clear();
}
@Override
public void destroy() throws Exception {
clear();
}
/**
* Get map associated with given key space.
*
* @param keyspace must not be {@literal null}.
* @return
*/
protected Map<Object, Object> getKeySpaceMap(String keyspace) {
Assert.notNull(keyspace, "Collection must not be null for lookup");
return store.getKeySpace(keyspace);
}
}