mirror of https://github.com/apache/lucene.git
SOLR-13841: removed jackson dependencies from SolrJ and provided a mapping to our annotation (#992)
Provide mappings for jackson annotation @JsonProperty to use Jackson deserializer
This commit is contained in:
parent
7f7730d6bc
commit
b5f5b0f2bc
|
@ -153,7 +153,7 @@ Other Changes
|
|||
|
||||
* SOLR-12769: Fix incorrect documentation for 'delete' op in Request parameters API (Alexandre Rafalovitch, Munendra S N)
|
||||
|
||||
* SOLR-13841: Add jackson databind annotations to SolrJ classpath (noble)
|
||||
* Provide mappings for jackson annotation @JsonProperty to use Jackson deserializer (noble)
|
||||
|
||||
* SOLR-13824: Strictly reject anything after JSON in most APIs (Mikhail Khludnev, Munendra S N)
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.apache.solr.api;
|
|||
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
@ -33,18 +32,19 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.solr.client.solrj.SolrRequest;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.SpecProvider;
|
||||
import org.apache.solr.common.util.CommandOperation;
|
||||
import org.apache.solr.common.util.JsonSchemaCreator;
|
||||
import org.apache.solr.common.util.Utils;
|
||||
import org.apache.solr.common.util.ValidatingJsonMap;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.security.AuthorizationContext;
|
||||
import org.apache.solr.security.PermissionNameProvider;
|
||||
import org.apache.solr.util.SolrJacksonAnnotationInspector;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -61,7 +61,7 @@ import org.slf4j.LoggerFactory;
|
|||
public class AnnotatedApi extends Api implements PermissionNameProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
public static final String ERR ="Error executing commands :";
|
||||
public static final String ERR = "Error executing commands :";
|
||||
private EndPoint endPoint;
|
||||
private Map<String, Cmd> commands = new HashMap<>();
|
||||
private final Api fallback;
|
||||
|
@ -137,7 +137,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
|
|||
}
|
||||
}
|
||||
|
||||
List<CommandOperation> cmds = req.getCommands(false);
|
||||
List<CommandOperation> cmds = req.getCommands(true);
|
||||
boolean allExists = true;
|
||||
for (CommandOperation cmd : cmds) {
|
||||
if (!commands.containsKey(cmd.name)) {
|
||||
|
@ -161,8 +161,8 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
|
|||
|
||||
List<Map> errs = CommandOperation.captureErrors(cmds);
|
||||
if (!errs.isEmpty()) {
|
||||
log.error(ERR+ Utils.toJSONString(errs));
|
||||
throw new ApiBag.ExceptionWithErrObject(SolrException.ErrorCode.BAD_REQUEST, ERR , errs);
|
||||
log.error(ERR + Utils.toJSONString(errs));
|
||||
throw new ApiBag.ExceptionWithErrObject(SolrException.ErrorCode.BAD_REQUEST, ERR, errs);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
|
|||
|
||||
|
||||
Cmd(Command command, Object obj, Method method) {
|
||||
mapper.setAnnotationIntrospector(SolrJacksonAnnotationInspector.INSTANCE);
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
this.command = command;
|
||||
this.obj = obj;
|
||||
|
@ -253,61 +254,20 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private static final Map<Class, String> primitives = new HashMap<>();
|
||||
|
||||
static {
|
||||
primitives.put(String.class, "string");
|
||||
primitives.put(Integer.class, "integer");
|
||||
primitives.put(int.class, "integer");
|
||||
primitives.put(Float.class, "number");
|
||||
primitives.put(float.class, "number");
|
||||
primitives.put(Double.class, "number");
|
||||
primitives.put(double.class, "number");
|
||||
primitives.put(Boolean.class, "boolean");
|
||||
primitives.put(List.class, "array");
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, Object> createSchema(Method m) {
|
||||
Type[] types = m.getGenericParameterTypes();
|
||||
if (types.length == 3) {
|
||||
return createSchemaFromType(types[2]);
|
||||
Type t = types[2];
|
||||
if (t instanceof ParameterizedType) {
|
||||
ParameterizedType typ = (ParameterizedType) t;
|
||||
if (typ.getRawType() == PayloadObj.class) {
|
||||
t = typ.getActualTypeArguments()[0];
|
||||
}
|
||||
}
|
||||
return JsonSchemaCreator.getSchema(t);
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Map<String, Object> createSchemaFromType(Type t) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
if (t instanceof ParameterizedType) {
|
||||
ParameterizedType typ = (ParameterizedType) t;
|
||||
if (typ.getRawType() == PayloadObj.class) {
|
||||
t = typ.getActualTypeArguments()[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (primitives.containsKey(t)) {
|
||||
map.put("type", primitives.get(t));
|
||||
} else if (t instanceof ParameterizedType && ((ParameterizedType) t).getRawType() == List.class) {
|
||||
Type typ = ((ParameterizedType) t).getActualTypeArguments()[0];
|
||||
map.put("type", "array");
|
||||
map.put("items", createSchemaFromType(typ));
|
||||
} else {
|
||||
createObjectSchema((Class) t, map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void createObjectSchema(Class klas, Map<String, Object> map) {
|
||||
map.put("type", "object");
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
map.put("properties", props);
|
||||
for (Field fld : klas.getDeclaredFields()) {
|
||||
JsonProperty p = fld.getAnnotation(JsonProperty.class);
|
||||
if (p == null) continue;
|
||||
props.put(p.value(), createSchemaFromType(fld.getGenericType()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.solr.api.Command;
|
||||
import org.apache.solr.api.EndPoint;
|
||||
|
@ -34,6 +33,7 @@ import org.apache.solr.api.PayloadObj;
|
|||
import org.apache.solr.client.solrj.SolrRequest;
|
||||
import org.apache.solr.client.solrj.request.beans.Package;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
import org.apache.solr.common.cloud.SolrZkClient;
|
||||
import org.apache.solr.common.cloud.ZkStateReader;
|
||||
import org.apache.solr.common.cloud.ZooKeeperException;
|
||||
|
@ -44,6 +44,7 @@ import org.apache.solr.core.CoreContainer;
|
|||
import org.apache.solr.filestore.PackageStoreAPI;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.util.SolrJacksonAnnotationInspector;
|
||||
import org.apache.zookeeper.KeeperException;
|
||||
import org.apache.zookeeper.WatchedEvent;
|
||||
import org.apache.zookeeper.Watcher;
|
||||
|
@ -55,13 +56,16 @@ import static org.apache.solr.common.cloud.ZkStateReader.SOLR_PKGS_PATH;
|
|||
import static org.apache.solr.security.PermissionNameProvider.Name.PACKAGE_EDIT_PERM;
|
||||
import static org.apache.solr.security.PermissionNameProvider.Name.PACKAGE_READ_PERM;
|
||||
|
||||
/**This implements the public end points (/api/cluster/package) of package API.
|
||||
*
|
||||
*/
|
||||
public class PackageAPI {
|
||||
public static final String PACKAGES = "packages";
|
||||
public final boolean enablePackages = Boolean.parseBoolean(System.getProperty("enable.packages", "false"));
|
||||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
final CoreContainer coreContainer;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
private final PackageLoader packageLoader;
|
||||
Packages pkgs;
|
||||
|
||||
|
@ -71,6 +75,7 @@ public class PackageAPI {
|
|||
public PackageAPI(CoreContainer coreContainer, PackageLoader loader) {
|
||||
this.coreContainer = coreContainer;
|
||||
this.packageLoader = loader;
|
||||
mapper.setAnnotationIntrospector(SolrJacksonAnnotationInspector.INSTANCE);
|
||||
pkgs = new Packages();
|
||||
SolrZkClient zkClient = coreContainer.getZkController().getZkClient();
|
||||
try {
|
||||
|
@ -243,7 +248,7 @@ public class PackageAPI {
|
|||
packages = new Packages();
|
||||
}
|
||||
packages.packages.computeIfAbsent(add.pkg, Utils.NEW_ARRAYLIST_FUN).add(new PkgVersion(add));
|
||||
packages.znodeVersion = stat.getVersion() + 1;
|
||||
packages.znodeVersion = stat.getVersion() ;
|
||||
finalState[0] = packages;
|
||||
return Utils.toJSON(packages);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.solr.util;
|
||||
|
||||
import com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
||||
import com.fasterxml.jackson.databind.PropertyName;
|
||||
import com.fasterxml.jackson.databind.introspect.Annotated;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
|
||||
import com.fasterxml.jackson.databind.util.BeanUtil;
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
|
||||
/**this class provides a mapping between Solr's {@link JsonProperty} annotation to a corresponding annotation
|
||||
* in jackson
|
||||
see SOLR-13841 for more details
|
||||
* <blockquote><pre>
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setAnnotationIntrospector(new SolrJacksonAnnotationInspector());
|
||||
* </pre></blockquote>
|
||||
**/
|
||||
public class SolrJacksonAnnotationInspector extends AnnotationIntrospector {
|
||||
public static final SolrJacksonAnnotationInspector INSTANCE = new SolrJacksonAnnotationInspector();
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return Version.unknownVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyName findNameForSerialization(Annotated a) {
|
||||
if (a instanceof AnnotatedMethod) {
|
||||
AnnotatedMethod am = (AnnotatedMethod) a;
|
||||
JsonProperty prop = am.getAnnotation(JsonProperty.class);
|
||||
if (prop == null) return null;
|
||||
if (prop.value().isEmpty()) {
|
||||
return new PropertyName(BeanUtil.okNameForGetter(am, true));
|
||||
} else {
|
||||
return new PropertyName(prop.value());
|
||||
}
|
||||
|
||||
}
|
||||
if (a instanceof AnnotatedField) {
|
||||
AnnotatedField af = (AnnotatedField) a;
|
||||
JsonProperty prop = af.getAnnotation(JsonProperty.class);
|
||||
if (prop == null) return null;
|
||||
return prop.value().isEmpty() ?
|
||||
new PropertyName(af.getName()) :
|
||||
new PropertyName(prop.value());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean hasRequiredMarker(AnnotatedMember m) {
|
||||
JsonProperty prop = m.getAnnotation(JsonProperty.class);
|
||||
if (prop == null) return Boolean.FALSE;
|
||||
return prop.required();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findPropertyDefaultValue(Annotated m) {
|
||||
JsonProperty prop = m.getAnnotation(JsonProperty.class);
|
||||
if (prop == null) return "";
|
||||
return prop.defaultValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyName findNameForDeserialization(Annotated a) {
|
||||
return findNameForSerialization(a);
|
||||
}
|
||||
|
||||
}
|
|
@ -27,7 +27,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.api.AnnotatedApi;
|
||||
import org.apache.solr.api.Api;
|
||||
|
@ -37,6 +36,7 @@ import org.apache.solr.api.EndPoint;
|
|||
import org.apache.solr.api.V2HttpCall;
|
||||
import org.apache.solr.api.V2HttpCall.CompositeApi;
|
||||
import org.apache.solr.client.solrj.SolrRequest;
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
import org.apache.solr.common.params.MapSolrParams;
|
||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.solr.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.solr.SolrTestCase;
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
import org.apache.solr.common.util.JsonSchemaCreator;
|
||||
import org.apache.solr.common.util.JsonSchemaValidator;
|
||||
import org.apache.solr.common.util.Utils;
|
||||
|
||||
public class TestSolrJacksonAnnotation extends SolrTestCase {
|
||||
|
||||
public void testSerDe() throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setAnnotationIntrospector(new SolrJacksonAnnotationInspector());
|
||||
|
||||
TestObj o = new TestObj();
|
||||
o.field = "v1";
|
||||
o.f2 = "v2";
|
||||
o.ifld = 1234;
|
||||
String json = mapper.writeValueAsString(o);
|
||||
|
||||
Map m = (Map) Utils.fromJSONString(json);
|
||||
assertEquals("v1", m.get("field"));
|
||||
assertEquals("v2", m.get("friendlyName"));
|
||||
assertEquals("1234", String.valueOf(m.get("friendlyIntFld")));
|
||||
TestObj o1 = mapper.readValue(json, TestObj.class);
|
||||
|
||||
assertEquals("v1", o1.field);
|
||||
assertEquals("v2", o1.f2);
|
||||
assertEquals(1234, o1.ifld);
|
||||
|
||||
Map<String, Object> schema = JsonSchemaCreator.getSchema(TestObj.class);
|
||||
assertEquals("string", Utils.getObjectByPath(schema,true,"/properties/friendlyName/type"));
|
||||
assertEquals("integer", Utils.getObjectByPath(schema,true,"/properties/friendlyIntFld/type"));
|
||||
assertEquals("friendlyName", Utils.getObjectByPath(schema,true,"/required[0]"));
|
||||
|
||||
|
||||
JsonSchemaValidator validator = new JsonSchemaValidator(schema);
|
||||
List<String> errs = validator.validateJson(m);
|
||||
assertNull(errs);
|
||||
m.remove("friendlyName");
|
||||
errs = validator.validateJson(m);
|
||||
assertFalse(errs.isEmpty());
|
||||
assertTrue(errs.get(0).contains("Missing required attribute"));
|
||||
m.put("friendlyIntFld", Boolean.TRUE);
|
||||
errs = validator.validateJson(m);
|
||||
m.put("friendlyIntFld", "another String");
|
||||
assertTrue(errs.get(0).contains("Value is not valid"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static class TestObj {
|
||||
@JsonProperty()
|
||||
public String field;
|
||||
@JsonProperty(value = "friendlyName" ,required = true)
|
||||
public String f2;
|
||||
@JsonProperty("friendlyIntFld")
|
||||
public int ifld;
|
||||
}
|
||||
}
|
|
@ -61,8 +61,6 @@
|
|||
<dependency org="io.netty" name="netty-transport-native-epoll" rev="${/io.netty/netty-transport-native-epoll}" conf="compile"/>
|
||||
<dependency org="io.netty" name="netty-transport-native-unix-common" rev="${/io.netty/netty-transport-native-unix-common}" conf="compile"/>
|
||||
|
||||
<dependency org="com.fasterxml.jackson.core" name="jackson-annotations" rev="${/com.fasterxml.jackson.core/jackson-annotations}" conf="compile"/>
|
||||
|
||||
<dependency org="org.apache.logging.log4j" name="log4j-slf4j-impl" rev="${/org.apache.logging.log4j/log4j-slf4j-impl}" conf="test"/>
|
||||
|
||||
<dependency org="org.mockito" name="mockito-core" rev="${/org.mockito/mockito-core}" conf="test"/>
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.apache.solr.client.solrj.io.Tuple;
|
|||
import org.apache.solr.client.solrj.io.comp.StreamComparator;
|
||||
import org.apache.solr.client.solrj.io.eval.DbscanEvaluator;
|
||||
import org.apache.solr.client.solrj.io.eval.KmeansEvaluator;
|
||||
import org.apache.solr.client.solrj.io.eval.StreamEvaluator;
|
||||
import org.apache.solr.client.solrj.io.eval.Matrix;
|
||||
import org.apache.solr.client.solrj.io.eval.StreamEvaluator;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.Explanation;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.Explanation.ExpressionType;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.Expressible;
|
||||
|
|
|
@ -19,7 +19,7 @@ package org.apache.solr.client.solrj.request.beans;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
import org.apache.solr.common.util.ReflectMapWriter;
|
||||
|
||||
/**Just a container class for POJOs used in Package APIs
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Data objects used in V2 Requests with jackson bindings
|
||||
* Annotated Data objects used in V2 Requests
|
||||
*/
|
||||
package org.apache.solr.client.solrj.request.beans;
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.solr.common.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**Provides a 1:1 mapping from jackson's annotation. This was created to avoid direct dependency on jackson in SolrJ
|
||||
*
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface JsonProperty {
|
||||
|
||||
String value() default "";
|
||||
|
||||
boolean required() default false;
|
||||
// not implemented
|
||||
// int index() default -1;
|
||||
|
||||
String defaultValue() default "";
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.solr.common.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
|
||||
/**Creates a json schema from an annotated Java Object. This, by no means, is an exhaustive impl
|
||||
* of schema generation. We will expand the scope as we use more types
|
||||
*
|
||||
*/
|
||||
|
||||
public class JsonSchemaCreator {
|
||||
public static final Map<Class, String> natives = new HashMap<>();
|
||||
|
||||
static {
|
||||
natives.put(String.class, "string");
|
||||
natives.put(Integer.class, "integer");
|
||||
natives.put(int.class, "integer");
|
||||
natives.put(Float.class, "number");
|
||||
natives.put(float.class, "number");
|
||||
natives.put(Double.class, "number");
|
||||
natives.put(double.class, "number");
|
||||
natives.put(Boolean.class, "boolean");
|
||||
natives.put(List.class, "array");
|
||||
}
|
||||
|
||||
public static Map<String, Object> getSchema(java.lang.reflect.Type t) {
|
||||
return createSchemaFromType(t, new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
private static Map<String, Object> createSchemaFromType(java.lang.reflect.Type t, Map<String, Object> map) {
|
||||
if (natives.containsKey(t)) {
|
||||
map.put("type", natives.get(t));
|
||||
} else if (t instanceof ParameterizedType && ((ParameterizedType) t).getRawType() == List.class) {
|
||||
Type typ = ((ParameterizedType) t).getActualTypeArguments()[0];
|
||||
map.put("type", "array");
|
||||
map.put("items", getSchema(typ));
|
||||
} else {
|
||||
createObjectSchema((Class) t, map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void createObjectSchema(Class klas, Map<String, Object> map) {
|
||||
map.put("type", "object");
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
map.put("properties", props);
|
||||
Set<String> required = new HashSet<>();
|
||||
for (Field fld : klas.getDeclaredFields()) {
|
||||
JsonProperty p = fld.getAnnotation(JsonProperty.class);
|
||||
if (p == null) continue;
|
||||
String name = p.value().isEmpty() ? fld.getName() : p.value();
|
||||
props.put(name, getSchema(fld.getGenericType()));
|
||||
if(p.required()) required.add(name);
|
||||
}
|
||||
if(!required.isEmpty()) map.put("required", new ArrayList<>(required));
|
||||
|
||||
}
|
||||
}
|
|
@ -21,8 +21,9 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.solr.common.MapWriter;
|
||||
import org.apache.solr.common.annotation.JsonProperty;
|
||||
|
||||
// An implementation of MapWriter which is annotated with Jackson annotations
|
||||
public interface ReflectMapWriter extends MapWriter {
|
||||
|
||||
|
|
|
@ -21,15 +21,22 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
import org.apache.lucene.util.LuceneTestCase.Slow;
|
||||
import org.apache.solr.SolrTestCase;
|
||||
import org.apache.solr.client.solrj.io.eval.*;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorDay;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorDayOfQuarter;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorDayOfYear;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorEpoch;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorHour;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorMinute;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorMonth;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorQuarter;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorSecond;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorWeek;
|
||||
import org.apache.solr.client.solrj.io.eval.TemporalEvaluatorYear;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.Expressible;
|
||||
import org.apache.solr.client.solrj.io.stream.expr.StreamFactory;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@Slow
|
||||
|
|
Loading…
Reference in New Issue