/*
* Copyright 2012 - 2017 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 org.springframework.data.solr.core.convert;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.solr.client.solrj.beans.DocumentObjectBinder;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.solr.core.query.Update;
import org.springframework.data.solr.core.query.UpdateField;
import org.springframework.data.solr.core.query.ValueHoldingField;
import org.springframework.util.Assert;
/**
* Offers classes that can convert from SolrDocument to any Object and vice versa using the solrj DocumentObjectBinder
*
* @author Christoph Strobl
*/
final class SolrjConverters {
private SolrjConverters() {
}
abstract static class DocumentBinderConverter {
protected final DocumentObjectBinder documentObjectBinder;
public DocumentBinderConverter(DocumentObjectBinder binder) {
this.documentObjectBinder = binder != null ? binder : new DocumentObjectBinder();
}
}
/**
* Converts any {@link Object} to {@link SolrInputDocument}
*
* @author Christoph Strobl
*/
@WritingConverter
public static class ObjectToSolrInputDocumentConverter extends DocumentBinderConverter
implements Converter<Object, SolrInputDocument> {
public ObjectToSolrInputDocumentConverter(DocumentObjectBinder binder) {
super(binder);
}
@Override
public SolrInputDocument convert(Object source) {
if (source == null) {
return null;
}
return documentObjectBinder.toSolrInputDocument(source);
}
}
/**
* Converts any {@link Update} to {@link SolrInputDocument} for atomic update.
*
* @author Christoph Strobl
*/
@WritingConverter
public static class UpdateToSolrInputDocumentConverter implements Converter<Update, SolrInputDocument> {
private static final String VERSION_FIELD_ID = "_version_";
public UpdateToSolrInputDocumentConverter() {
super();
}
@Override
public SolrInputDocument convert(Update source) {
if (source == null) {
return null;
}
Assert.notNull(source.getIdField(), "Id field must not be null!");
Assert.hasText(source.getIdField().getName(), "Name of Id field must not be null nor empty!");
SolrInputDocument solrInputDocument = new SolrInputDocument();
solrInputDocument.addField(source.getIdField().getName(), source.getIdField().getValue());
if (source.getVersion() != null) {
solrInputDocument.addField(VERSION_FIELD_ID, source.getVersion());
}
for (UpdateField field : source.getUpdates()) {
HashMap<String, Object> mapValue = new HashMap<>(1);
mapValue.put(field.getAction().getSolrOperation(), getUpdateValue(field));
solrInputDocument.addField(field.getName(), mapValue);
}
return solrInputDocument;
}
private Object getUpdateValue(ValueHoldingField field) {
// Solr removes all values from document in case of empty colleciton
// therefore those values have to be set to null.
if (field.getValue() instanceof Collection) {
if (((Collection<?>) field.getValue()).isEmpty()) {
return null;
}
}
return field.getValue();
}
}
/**
* Convert any {@link SolrDocument} to object of given {@link Class} using {@link DocumentObjectBinder}
*
* @author Christoph Strobl
* @param <T>
*/
@ReadingConverter
public static class SolrInputDocumentToObjectConverter<T> extends DocumentBinderConverter
implements Converter<Map<String, ?>, T> {
private Class<T> clazz;
public SolrInputDocumentToObjectConverter(Class<T> clazz) {
this(clazz, null);
}
public SolrInputDocumentToObjectConverter(Class<T> clazz, DocumentObjectBinder binder) {
super(binder);
this.clazz = clazz;
}
@Override
public T convert(Map<String, ?> source) {
if (source == null) {
return null;
}
SolrDocument document = new SolrDocument();
document.putAll(source);
return documentObjectBinder.getBean(clazz, document);
}
}
}