Here is my BeanShell script which I wrote in JMeter
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
JSONObject outerObject = new JSONObject();
JSONArray jsonArray = new JSONArray();
for(int i = 0;i<=3;i++)
{
JSONObject innerObject = new JSONObject();
innerObject.put("middleName", "${__RandomString(4,KLMNOPRSTUVWXYZ,)}");
innerObject.put("maidenName", "${__RandomString(4,HUDNSERTFG,)}");
innerObject.put("gender", "${__RandomString(1,MFU,)}");
innerObject.put("TestingType", "${__RandomString(1,IE,)}");
jsonArray.put(innerObject);
outerObject.put("nameList", jsonArray);
}
outerObject.put("Alert", "Testing Alert");
log.info(outerObject.toString());
vars.putObject("jsonData",jsonArray);
Here is the JSON response which I am getting
{
"nameList": [
{
"gender": "M",
"maidenName": "DUDT",
"middleName": "ZPMZ",
"TestingType": "E"
},
{
"gender": "M",
"maidenName": "DUDT",
"middleName": "ZPMZ",
"TestingType": "E"
},
{
"gender": "M",
"maidenName": "DUDT",
"middleName": "ZPMZ",
"TestingType": "E"
},
{
"gender": "M",
"maidenName": "DUDT",
"middleName": "ZPMZ",
"TestingType": "E"
}
],
"Alert": "Testing Alert"
}
As you can see the JSON above, all the values are duplicated. I want to have different values for all the variable. Am I missing anything? Please guide me if anything wrong with my code. Thanks.
I would suggest using JSR223 + Groovy for performances with below code using RandomStringGenerator:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.apache.commons.text.RandomStringGenerator;
JSONObject outerObject = new JSONObject();
JSONArray jsonArray = new JSONArray();
RandomStringGenerator generator = new RandomStringGenerator.Builder().selectFrom("KLMNOPRSTUVWXYZ".toCharArray()).build();
RandomStringGenerator generatorGender = new RandomStringGenerator.Builder().selectFrom("MFU".toCharArray()).build();
RandomStringGenerator generatorType = new RandomStringGenerator.Builder().selectFrom("IE".toCharArray()).build();
for(int i = 0;i<=3;i++)
{
JSONObject innerObject = new JSONObject();
innerObject.put("middleName", generator.generate(4));
innerObject.put("maidenName", generator.generate(4));
innerObject.put("gender", generatorGender.generate(1));
innerObject.put("TestingType", generatorType.generate(1));
jsonArray.put(innerObject);
outerObject.put("nameList", jsonArray);
}
outerObject.put("Alert", "Testing Alert");
log.info(outerObject.toString());
vars.putObject("jsonData",jsonArray);
Related
I'm trying to use an elasticsearch script query using the Java SDK to determine if a collection of IDs passed as a parameter contains all of the values in the indexed document.
Here is a simple example, that does not work, i'm expecting this to match the a document, but it doesn't.
The document attributes field is an array with a single item [2]
BoolQueryBuilder qb = boolQuery();
Map<String, Object> params = new HashMap<String, Object>();
params.put( "list", Arrays.asList( 1L, 2L, 3L ) );
String expr = "params.list.containsAll(doc['attributes'])";
Script script = new Script( ScriptType.INLINE, "painless", expr, Collections.emptyMap(), params );
qb.should( scriptQuery( script ) );
However, i've tried these various hard coded alternatives that do work
Hard coded .contains(2) works as expected
BoolQueryBuilder qb = boolQuery();
Map<String, Object> params = new HashMap<String, Object>();
params.put( "list", Arrays.asList( 2L ) );
String expr = "params.list.contains(2)";
Script script = new Script( ScriptType.INLINE, "painless", expr, Collections.emptyMap(), params );
qb.should( scriptQuery( script ) );
Hard coded .containsAll([2]) works as expected
BoolQueryBuilder qb = boolQuery();
Map<String, Object> params = new HashMap<String, Object>();
params.put( "list", Arrays.asList( 2L ) );
String expr = "params.list.containsAll([2])";
Script script = new Script( ScriptType.INLINE, "painless", expr, Collections.emptyMap(), params );
qb.should( scriptQuery( script ) );
Gotta cast the params.list elements before calling containsAll:
{
"query": {
"bool": {
"must": [
{
"script": {
"script": {
"inline": """
params.list.stream()
.map(num -> (long) num)
.collect(Collectors.toList())
.containsAll(
doc['attributes'].stream()
.collect(Collectors.toList()))""",
"params": {
"list": [
2
]
}
}
}
}
]
}
}
}
assuming your mapping truly defined the atributes as such:
{
"mappings": {
"properties": {
"attributes": {
"type": "long"
}
}
}
}
I am using ServiceNow develop instance to create a table, in which one field is type of list. The values of the list is populated by Outgoing Rest message.
In business rule, I make a hard coded to see how list values shall be what kind of form. The codes lists as below/1/: but when I update the field computer room, the computerlist's value is not populated. It looks like in the image/2/. How to populate values to a list type of field?
/3/ is the json string returned in pretty format. I try to populate hostName to computerlist, but failed.
/1/ scripts in business rule:
(function executeRule(current, previous /*null when async*/ ) {
try {
var r = new sn_ws.RESTMessageV2('x_383581_aiademo2.AIACmdbReq', 'Default GET');
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
// var responseObj = JSON.parse(responseBody);
current.computerlist = new Array;
current.computerlist[0] = "c1";
current.computerlist[1] = "c2";
current.computerlist[2] = "c3";
current.assignto = "How to make it as list";
current.update();
} catch (ex) {
var message = ex.message;
}
})(current, previous);
/2/
/3/
{
"code": 200,
"data": {
"dataList": [
{
"hostName": "MysqlServer",
"deviceIp": "192.168.1.40",
"site": "SH",
"hostId": "00000000",
"location": "Room01",
"id": 9381947
},
{
"hostName": "192.168.1.32",
"deviceIp": "192.168.1.32",
"site": "SH",
"hostId": "a8c02001",
"location": "66666",
"id": 9381950
},
{
"hostName": "back-server",
"deviceIp": "192.168.1.42",
"site": "SH",
"hostId": "00000000",
"location": "Room01",
"id": 9381996
},
{
"hostName": "192.168.1.32",
"deviceIp": "192.168.1.32",
"site": "SH",
"hostId": "00-0C-29-E0-31-32",
"location": "Room01",
"id": 9382011
},
{
"hostName": "core-server1",
"deviceIp": "192.168.1.30",
"site": "SH",
"hostId": "00000000",
"location": "Room01",
"id": 9382014
}
]
},
"msg": "success"
}
/4/ business rule script is updated to:
(function executeRule(current, previous /*null when async*/ ) {
try {
var r = new sn_ws.RESTMessageV2('x_383581_aiademo2.AIACmdbReq', 'Default GET');
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
var responseObj = JSON.parse(responseBody);
current.computerlist = responseObj.data.dataList.hostName;
current.assignto = responseObj.code;
current.update();
} catch (ex) {
var message = ex.message;
}
})(current, previous);
The answer is as follows:
(function executeRule(current, previous /*null when async*/ ) {
try {
var r = new sn_ws.RESTMessageV2('x_383581_aiademo2.AIACmdbReq', 'Default GET');
var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
var responseObj = JSON.parse(responseBody);
var listLength = responseObj.data.dataList.length;
current.responsetest = responseObj.data.dataList[0].hostName;
var temp = new Array(listLength);
for(var j = 0; j<listLength; j++){
temp[j] = responseObj.data.dataList[j].hostName;
}
current.computerlist.setValue(temp);
current.assignto = temp[0];
current.vers = "0.0.1a";
current.description = responseObj.msg;
current.update();
////////////////////////good way///////////////////////////////
///////////current.computerlist.setValue(["1","2","3","4","5"]);
///////////////////////////////////////////////////////////////
} catch (ex) {
var message = ex.message;
}
})(current, previous);
I am trying to return a response body in my "successfullAuthentication" method in "UsernamePasswordAuthenticationFilter" using HATEOAS, but is returning the links in this format:
"links": [
{
"rel": "self",
"href": "http://localhost:8080/api/users/5c55ee26911e9f04acb77c91",
"hreflang": null,
"media": null,
"title": null,
"type": null,
"deprecation": null
},
I would like it to return HAL json format so it would look like this:
"_links": {
"self": {
"href": "http://localhost:8080/api/users/5c55ee26911e9f04acb77c91"
},
I have this in my method (response is HttpServletResponse):
User user = userService.findById(authResult.getName());
String json = Jackson.toJsonString(userResourceAssembler.toResource(user));
response.setContentType("application/hal+json");
response.setCharacterEncoding("UTF-8");
response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token);
response.getWriter().write(json);
I also have this in my WebConfig: #EnableHypermediaSupport(type = { EnableHypermediaSupport.HypermediaType.HAL })
Does anyone know why this is happening?
I found the answer in this github issue: https://github.com/spring-projects/spring-hateoas/issues/270#issuecomment-145606558
Basically:
private String convertToHalString(ResourceSupport resource) {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jackson2HalModule());
mapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(
new EvoInflectorRelProvider(), null, null));
String resourceString = null;
try {
resourceString = mapper.writeValueAsString(resource);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return resourceString;
}
Try to extend all model classes- to add HATEOAS links –
with org.springframework.hateoas.ResourceSupport class
Presuming you have respective URI's in controller class
Link link = ControllerLinkBuilder
.linkTo(UserController.class)
.slash(user.getXXX())
.withSelfRel();
//for single resource
user.add(link);
Link userLink = ControllerLinkBuilder
.linkTo(ControllerLinkBuilder
.methodOn(UserController.class).getAllUsers())
.withSelfRel();
//For collections
userList.add(userLink);
Reference: https://spring.io/understanding/HATEOAS
I'm working with an API rest and it returns me two types of json, object and array.
Object(When there is only one record in the database):
{ "complain": { "id": "1" , "description": "hello", "date": "2017-01-24 11:46:22", "Lat": "20.5204446", "Long": "-100.8249097" } }
Array(When there is more than one record in the database):
{ "complain": [ { "id": "1" , "description": "hello", "date": "2017-01-24 11:46:22", "Lat": "20.587446", "Long": "-100.8246490" }, { "id": "2" , "description": "hello 2", "date": "2017-01-24 11:50:12", "Lat": "20.529876", "Long": "-100.8249097" } ] }
The code I use to consume the json is as follows:
content = await response.Content.ReadAsStringAsync();
var token = JToken.Parse(content);
if (token["complain"] is JArray)
{
var jsonArray = JsonConvert.DeserializeObject<RootArray>(content);
}
else if (token["complain"] is JObject)
{
var jsonObject = JsonConvert.DeserializeObject<RootObject>(content);
}
When it comes to a json array if I can add it to a listview:
myList.ItemsSource = jsonArray.listArray;
But if it is an object I can not and I get the following error:
Cannot implicitly convert type Object to IEnumerable.
Finally I was able to solve my error, it was just a matter of creating a list and adding the deserialized json object.
var jsonObject = JsonConvert.DeserializeObject<RootObject>(content);
List<Complain> simpleList = new List<Complain>();
simpleList.Add(jsonObject.ComplainObject);
myList.ItemsSource = simpleList;
The class to deserialize the Json object:
public class RootObject
{
[JsonProperty("complain")]
public Complain ComplainObject { get; set; }
}
it seems that SpringData ES don't provide classes to fetch highlights returned by ES. Spring Data can return Lists of Objects but the highlights sections in the Json returned by ES is in a separated part that is not handled by the "ElasticSearchTemplate" class.
Code example :-
QueryBuilder query = QueryBuilders.matchQuery("name","tom");
SearchQuery searchQuery =new NativeSearchQueryBuilder().withQuery(query).
with HighlightFields(new Field("name")).build();
List<ESDocument> publications = elasticsearchTemplate.queryForList
(searchQuery, ESDocument.class);
I might be wrong, but I can't figure out to do only with SpringDataES. Someone can post an example of how we can get highlights with Spring Data ES ?
Thanks in advance !
From the test cases in spring data elasticsearch I've found solution to this :
This can be helpful.
#Test
public void shouldReturnHighlightedFieldsForGivenQueryAndFields() {
//given
String documentId = randomNumeric(5);
String actualMessage = "some test message";
String highlightedMessage = "some <em>test</em> message";
SampleEntity sampleEntity = SampleEntity.builder().id(documentId)
.message(actualMessage)
.version(System.currentTimeMillis()).build();
IndexQuery indexQuery = getIndexQuery(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(termQuery("message", "test"))
.withHighlightFields(new HighlightBuilder.Field("message"))
.build();
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
#Override
public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}
SampleEntity user = new SampleEntity();
user.setId(searchHit.getId());
user.setMessage((String) searchHit.getSource().get("message"));
user.setHighlightedMessage(searchHit.getHighlightFields().get("message").fragments()[0].toString());
chunk.add(user);
}
if (chunk.size() > 0) {
return new PageImpl<T>((List<T>) chunk);
}
return null;
}
});
assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage));
}
Spring Data Elasticsearch 4.0 now has the SearchPage result type, which makes things a little easier if we need to return highlighted results:
This is a working sample:
String query = "(id:123 OR id:456) AND (database:UCLF) AND (services:(sealer?), services:electronic*)"
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withPageable(pageable)
.withQuery(queryStringQuery(query))
.withSourceFilter(sourceFilter)
.withHighlightFields(new HighlightBuilder.Field("goodsAndServices"))
.build();
SearchHits<Trademark> searchHits = template.search(searchQuery, Trademark.class, IndexCoordinates.of("trademark"));
SearchPage<Trademark> page = SearchHitSupport.searchPageFor(searchHits, searchQuery.getPageable());
return (Page<Trademark>) SearchHitSupport.unwrapSearchHits(page);
And this would be the response from Page object in json:
{
"content": [
{
"id": "123",
"score": 12.10748,
"sortValues": [],
"content": {
"_id": "1P0XzXIBdRyrchmFplEA",
"trademarkIdentifier": "abc234",
"goodsAndServices": null,
"language": "EN",
"niceClass": "2",
"sequence": null,
"database": "UCLF",
"taggedResult": null
},
"highlightFields": {
"goodsAndServices": [
"VARNISHES, <em>SEALERS</em>, AND NATURAL WOOD FINISHES"
]
}
}
],
"pageable": {
"sort": {
"unsorted": true,
"sorted": false,
"empty": true
},
"offset": 0,
"pageNumber": 0,
"pageSize": 20,
"unpaged": false,
"paged": true
},
"searchHits": {
"totalHits": 1,
"totalHitsRelation": "EQUAL_TO",
"maxScore": 12.10748,
"scrollId": null,
"searchHits": [
{
"id": "123",
"score": 12.10748,
"sortValues": [],
"content": {
"_id": "1P0XzXIBdRyrchmFplEA",
"trademarkIdentifier": "abc234",
"goodsAndServices": null,
"language": "EN",
"niceClass": "2",
"sequence": null,
"database": "UCLF",
"taggedResult": null
},
"highlightFields": {
"goodsAndServices": [
"VARNISHES, <em>SEALERS</em>, AND NATURAL WOOD FINISHES"
]
}
}
],
"aggregations": null,
"empty": false
},
"totalPages": 1,
"totalElements": 1,
"size": 20,
"number": 0,
"numberOfElements": 1,
"last": true,
"first": true,
"sort": {
"unsorted": true,
"sorted": false,
"empty": true
},
"empty": false
}
Actually, you could do the following, with a custom ResultExtractor:
QueryBuilder query = QueryBuilders.matchQuery("name", "tom");
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(query)
.withHighlightFields(new Field("name")).build();
return elasticsearchTemplate.query(searchQuery.build(), new CustomResultExtractor());
And then
public class CustomResultExtractor implements ResultsExtractor<List<MyClass>> {
private final DefaultEntityMapper defaultEntityMapper;
public CustomResultExtractor() {
defaultEntityMapper = new DefaultEntityMapper();
}
#Override
public List<MyClass> extract(SearchResponse response) {
return StreamSupport.stream(response.getHits().spliterator(), false)
.map(this::searchHitToMyClass)
.collect(Collectors.toList());
}
private MyClass searchHitToMyClass(SearchHit searchHit) {
MyElasticSearchObject myObject;
try {
myObject = defaultEntityMapper.mapToObject(searchHit.getSourceAsString(), MyElasticSearchObject.class);
} catch (IOException e) {
throw new ElasticsearchException("failed to map source [ " + searchHit.getSourceAsString() + "] to class " + MyElasticSearchObject.class.getSimpleName(), e);
}
List<String> highlights = searchHit.getHighlightFields().values()
.stream()
.flatMap(highlightField -> Arrays.stream(highlightField.fragments()))
.map(Text::string)
.collect(Collectors.toList());
// Or whatever you want to do with the highlights
return new MyClass(myObject, highlights);
}}
Note that I used a list but you could use any other iterable data structure. Also, you could do something else with the highlights. Here I'm simply listing them.
https://stackoverflow.com/a/37163711/6643675
The first answer does works,but I found some pageable problems with its returned result,which display with the wrong total elements and toalpages.Arter I checkout the DefaultResultMapper implementation, the returned statement shoud be return new AggregatedPageImpl((List<T>) chunk, pageable, totalHits, response.getAggregations(), response.getScrollId(), maxScore);,and then it works with paging.wish i could help you guys~