MarkLogic: pass Map-Object from Java to XQuery - java

I would like to pass a simple Java Map<String, String> through the MarkLogic Java API to an XQuery script. The script is already deployed to the /ext directory on the server and starts like this:
xquery version "1.0-ml";
declare variable $dr as xs:string external;
declare variable $en as xs:string external;
declare variable $fi as map:map external;
...
I'm using the pattern described on the MarkLogic Site: https://docs.marklogic.com/guide/java/resourceservices#id_70532 ("Basic Steps for Module Invocation").
My Java code looks like this:
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
ServerEvaluationCall invoker = client.newServerEval();
invoker.addVariable("dr", "foo");
invoker.addVariable("en", "bar");
invoker.addVariableAs("fi", map);
String response = invoker.evalAs(String.class);
This fails with this exception:
java.lang.IllegalArgumentException: No factory for class java.util.HashMap
at com.marklogic.client.impl.HandleFactoryRegistryImpl.makeHandle(HandleFactoryRegistryImpl.java:98) ~[marklogic-client-api-4.0.3.jar:?]
at com.marklogic.client.impl.ServerEvaluationCallImpl.addVariableAs(ServerEvaluationCallImpl.java:123) ~[marklogic-client-api-4.0.3.jar:?]
I think I need to convert the map before sending it to ML or maybe use one of the handler classes, but I was not able to solve it or find any examples of this. Has anyone done this before?

It should work to pass a Jackson JSON object to an XQuery external variable. The value in XQuery should be either an XQuery map or a JSON node. If it's a JSON node, the xdmp:from-json() function can convert the value to an XQuery map.
For the Java part, look for the example introduced as "the following code uses a Jackson object mapper to set an external variable value to a JSON object":
https://docs.marklogic.com/guide/java/resourceservices#id_21827
Hoping that helps,

Related

How to convert JSON in QueryParams into Object in Java Spring?

I have this query
http://localhost:8555/list/csv?search={}
Where search is a json object (omitted other params as they are irrelevant here).
How can i convert this into a nested object?
public record CsvParams<T>(
T search,
/* Other query params */ ) {}
Right now im getting error that string cannot be cast into object.
class java.lang.String cannot be cast to class classname
Is there anyway to do this? Old solution uses ObjectMapper to convert string into corresbonding object. I was hoping that maybe there is a way to do it more simpli and remove this boilerplate.
Any single value of a query param can't be automatically converted to a non-primitive type. You can convert multiple params to a class, but not one that happens to be a JSON AFAIK. But you can create a converter custom deserialiser and then use it in different controllers, but in the end you'd still use an ObjectMapper.
More info on how to do the latter here: https://www.baeldung.com/spring-mvc-send-json-parameters
If you have to work with query params than I don't think you can have it converted automatically by Spring boot. But if you work with POST or PUT methods and can pass your params as request params in request body your JSON params can be automatically converted to class instances by Spring boot and no effort required from you. However, if you have to work with query param (say you have to use method GET so you have no request body) than you can use Json-Jackson library or Gson library to parse your Json into class instance. If you use Jackson you will need to use class ObjectMapper. For Jackson lib info see this site, for ObjectMapper class see Javadoc here. However, I wrote my own JsonUtils that is very good for simple usecases like yours. It allows to to parse simple JSON into a class with a single method. It is very simple and strait forward. It is a thin wrapper over Jackson library. See the Javadoc for method readObjectFromJsonString. Class JsonUtils is part of Open Source MgntUtils library. You can get it as Maven artifact on Maven Central and as a jar (with source code and Javadoc) on Github

handle environment variable in .yml with jackson-dataformat-yaml

I'm using jackson to retrive file .yml into pojo java.
It's working fine.
how could I handle environment variables in .yml when read to pojo? jackson has this implementation?
example:
attr1: ${ENV_ATTR} # read this value from environment when has ${}
Dependencie
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1'
Implementation code
var fileYml = new File(getClass().getClassLoader().getResource("file.yml").toURI());
var mapper = new ObjectMapper(new YAMLFactory());
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE);
var entityFromYml = mapper.readValue(fileYmlContent, MyEntity.class);
note: I'm not using spring or spring boot.
There's Apache Commons' StringSubstitutor which does the job.
You can either pre-process the input string with it, or post-process each loaded string.
Post-processing obviously works only on values that load into Strings so you can't use it e.g. on a value that loads into an int.
Pre-processing, on the other hand, is dangerous because it doesn't protect you against YAML special characters in the env variable's value. In your example, set ENV_ATTR to
foo
bar: baz
and after substitution, you will have
attr1: foo
bar: baz
which might not be desired.
If you want to guard against that but also want to substitute in non-String values, you'll need to use SnakeYAML's API directly and specialize its Composer. Jackson is an abstraction API on top of SnakeYAML that restricts what you can do, so this is not possible with Jackson.

How to get the map values from "yml" file as a Map?

I have a "details.yml" file, considering all the setting for getting all values from "yml.file" is done. But I am unable to store Map values into
"Map"
Here is my "details.yml" file below
details:
company:XYZ
values:
name: Manish
last: Raut
And in my class file i am able to get the values of "company" from yml file using #Value("${company}")
#Component
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "details")
public class abcd() {
#Value("${company}")
String company;
#Value("${values}")
Map<String, String> values =new HashMap<String, String>();
...............................
}
i am not able to get those values in Mao which i created in this class, but i am getting values for "Company".
Help me with this?
Im the past, I added getter/setter for MAP type and it was work.
Did you try it? (getter/setter for 'values')
I'm not really sure what marshalling framework Spring uses behind the scenes and how it configures it (you could probably find out with some debugging and maybe make it work for your case), but you could always add an extra layer to your application and configure your own.
For instance you could use Jackson with yaml dataformat - https://dzone.com/articles/read-yaml-in-java-with-jackson.

Serialize vertx JsonObject using Jackson

I'm using vertx and Jackson in my development. In one of my classes, I got a field of type JsonObject, something like this:
class User
private String name;
private JsonObject details;
This details field can contain other JsonObjects or JsonArrays, e.g.:
{"details": [{"street": "Broadway"}, {"building": 20}]}
I don't have a dedicated class of this structure, as far as there's no fixed structure and it can vary.
details object is being created in the way like this:
JsonObject details = new JsonObject().put("name", "value").put("another", "another")
This aproach allows me to store details of any structure inside my code. As far as I don't need to manipulate this data on my backend, I don't want to create a special structure for it.
Everything works fine until I'm trying to serialize this JsonObject using Jackson. Unfortunately, instead of beatiful JSON string, Jackson gives me map object serialized with all map's additional fields.
How can I serialize JsonObject of vertx using Jackson?
Looking at JsonObject's javadoc , I saw a getMap() method. I know Jackson is capable of serializing Maps with ease.
Finally, it turned out that vertx already has it's own implementation of Serializer.
It's enough just to use theirs class to perform serialization (which will use Jackson undercover).
JsonObject user = new JsonObject(Json.encode(new User());
And it works fine.
I would suggest creating using https://static.javadoc.io/com.fasterxml.jackson.core/jackson-databind/2.7.3/com/fasterxml/jackson/databind/ObjectMapper.html#convertValue(java.lang.Object,%20java.lang.Class) like this:
new JsonObject((Map)Json.mapper.convertValue(new User(), Map.class));
Converting to and from String takes time.

Creating Map or Set using GSON

I am using Google's GSON library and want to create a JSON which looks something like this:
{
"teamSet":[],
"classificationMap" : {}
}
Notice that [] and {} are empty Set and Map respectively and are not surrounded with double quotes.
I want to create this Json using the GSON add/addproperty method and not by converting a Java class into JSON using the Gson.toJson() method. The business use-case restricts me from creating specific Java classes as the JSON structure may change overtime. So I cannot use a class like this as this would rigidly tie a JSON structure with a concrete class
class Linkage{
private Set<String> teamSet;
private Map<String, String> classificationMap;
// getter, setter methods follow
...
}
When I use the GSON.addproperty(genericObject, type), it is appending double quotes around [] and {}. I am using couchbase for my DB requirements and the double quotes around [] and {} makes couchbase treat them as string and not as Set/Map. This renders my Map-Reduce views useless and buggy :(
Please let me know if its possible to create such a JSON without having to tie it up with a concrete JAVA class. Thanks !
My current code looks like this:
// create types
Type setType = new TypeToken<Set<String>>() {}.getType();
Type mapType = new TypeToken<Map<String, String>>() {}.getType();
Gson GSON = new Gson();
Set<String> teams = new HashSet<String>();
Map<String, String> classificationMap = new HashMap<String, String>();
JsonObject linkageJson = new JsonObject();
linkageJson.addProperty("teamSet", GSON.toJson(teams, setType));
linkageJson.addProperty("classificationMap", GSON.toJson(classificationMap, mapType));
In the 2.x line of the couchbase java sdk, there is the JsonObject class that could have fit your need.
It is perfect to create Json "by hand" and still have a simple generic object representation, and is the official way of putting json into the database via the sdk.
It would go like this :
JsonObject obj = JsonObject.create();
obj.put("teamSet", JsonArray.from(new ArrayList(teams)))
.put("classificationMap", JsonObject.from(classificationMap));
Granted this is a little bit contrived because arrays and sub-objects can only be constructed from respectively List<?> and Map<String, ?> factory methods. Also the class support a limited set of value types (no custom classes, only String, Number, Boolean, etc...).
i feel somewhere it is storing it toString() representation.
Please refer below link, it might help you.
click here

Categories

Resources