I am using json binding API to parse json string for application deployed on Liberty application server.
Suppose I have json string as given below
String message = "{ "color" : "Black", "type" : "BMW" }";
I want to iterate through json string and check every json property field (color/type) in the application logic to see if it contains some specific characters.
How can this be done using the json-b (Json Binding API)
Here is a simple example:
public class Car {
public String color;
public String type;
}
...
Jsonb jsonb = JsonbBuilder.create();
Car car = jsonb.fromJson("{ \"color\" : \"Black\", \"type\" : \"BMW\" }", Car.class);
if (car.color.contains("Bla") || car.type.startsWith("B"))
System.out.println("Found a " + car.type + " that is " + car.color);
jsonb.close();
Per section 3.11 of the JSON-B specification, implementations of JSON-B must support binding to java.util.LinkedHashMap (and a number of other standard collection types), so you can do the following if you don't know what the names of the fields are:
Jsonb jsonb = JsonbBuilder.create();
LinkedHashMap<String, ?> map = jsonb.fromJson("{ \"color\" : \"Black\", \"type\" : \"BMW\" }", LinkedHashMap.class);
for (Map.Entry<String, ?> entry : map.entrySet()) {
Object value = entry.getValue();
if (value instanceof String && ((String) value).contains("Black"))
System.out.println("Found " + entry.getKey() + " with value of " + value + " in " + map);
}
Related
I am trying to sort my table's content on the backend side, so I am sending org.springframework.data.domain.Pageable object to controller. It arrives correctly, but at the repository I am getting org.hibernate.hql.internal.ast.InvalidPathException. Somehow the field name I would use for sorting gets an org. package name infront of the filed name.
The Pageable object logged in the controller:
Page request [number: 0, size 10, sort: referenzNumber: DESC]
Exception in repository:
Invalid path: 'org.referenzNumber'","logger_name":"org.hibernate.hql.internal.ast.ErrorTracker","thread_name":"http-nio-8080-exec-2","level":"ERROR","level_value":40000,"stack_trace":"org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'org.referenzNumber'\n\tat org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:111)
My controller endpoint:
#GetMapping(value = "/get-orders", params = { "page", "size" }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<PagedModel<KryptoOrder>> getOrders(
#ApiParam(name = "searchrequest", required = true) #Validated final OrderSearchRequest orderSearchRequest,
#PageableDefault(size = 500) final Pageable pageable, final BindingResult bindingResult,
final PagedResourcesAssembler<OrderVo> pagedResourcesAssembler) {
if (bindingResult.hasErrors()) {
return ResponseEntity.badRequest().build();
}
PagedModel<Order> orderPage = PagedModel.empty();
try {
var orderVoPage = orderPort.processOrderSearch(resourceMapper.toOrderSearchRequestVo(orderSearchRequest), pageable);
orderPage = pagedResourcesAssembler.toModel(orderVoPage, orderAssembler);
} catch (MissingRequiredField m) {
log.warn(RESPONSE_MISSING_REQUIRED_FIELD, m);
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(orderPage);
}
the repository:
#Repository
public interface OrderRepository extends JpaRepository<Order, UUID> {
static final String SEARCH_ORDER = "SELECT o" //
+ " FROM Order o " //
+ " WHERE (cast(:partnerernumber as org.hibernate.type.IntegerType) is null or o.tradeBasis.account.retailpartner.partnerbank.partnerernumber = :partnerernumber)"
+ " and (cast(:accountnumber as org.hibernate.type.BigDecimalType) is null or o.tradeBasis.account.accountnumber = :accountnumber)"
+ " and (cast(:orderReference as org.hibernate.type.LongType) is null or o.tradeBasis.referenceNumber = :orderReference)"
+ " and (cast(:orderReferenceExtern as org.hibernate.type.StringType) is null or o.tradeBasis.kundenreferenceExternesFrontend = :orderReferenceExtern)"
+ " and (cast(:dateFrom as org.hibernate.type.DateType) is null or o.tradeBasis.timestamp > :dateFrom) "
+ " and (cast(:dateTo as org.hibernate.type.DateType) is null or o.tradeBasis.timestamp < :dateTo) ";
#Query(SEARCH_ORDER)
Page<Order> searchOrder(#Param("partnerernumber") Integer partnerernumber,
#Param("accountnumber") BigDecimal accountnumber, #Param("orderReference") Long orderReference,
#Param("orderReferenceExtern") String orderReferenceExtern, #Param("dateFrom") LocalDateTime dateFrom,
#Param("dateTo") LocalDateTime dateTo, Pageable pageable);
}
Update:
I removed the parameters from the sql query, and put them back one by one to see where it goes sideways. It seems as soon as the dates are involved the wierd "org." appears too.
Update 2:
If I change cast(:dateTo as org.hibernate.type.DateType) to cast(:dateFrom as date) then it appends the filed name with date. instead of org..
Thanks in advance for the help
My guess is, Spring Data is confused by the query you are using and can't properly append the order by clause to it. I would recommend you to use a Specification instead for your various filters. That will not only improve the performance of your queries because the database can better optimize queries, but will also make use of the JPA Criteria API behind the scenes, which requires no work from Spring Data to apply an order by specification.
Since your entity Order is named as the order by clause of HQL/SQL, my guess is that Spring Data tries to do something stupid with the string to determine the alias of the root entity.
I am a JPA newbie and wanted to have a JPA native query for a single table (below) which I would like to fetch in my #Entity based class called TestRequest. It has a column 'RequestTime' that is fetched with DAYNAME() and then with DATEDIFF() functions.
SELECT TestRequest.Id AS Id
, TestRequest.RequestTime AS RequestTime
, DAYNAME(TestRequest.RequestTime) AS RequestDay
, TestRequest.StatusMessage AS StatusMessage
, DATEDIFF(CURDATE(), TestRequest.RequestTime) AS HowLongAgo
FROM TestRequest
LEFT JOIN TestRun
ON TestRequest.TestRunId = TestRun.Id
WHERE Requestor = '[NAME]'
ORDER BY Id DESC
Is there any way in which the column (fetched second time as HowLongAgo) be set into a property which is not mapped to a table column within the TestRequest class? Are there any field level annotations for this?
You need to use Interface-based projections:
You will need to create an interface that define the getters for each field in your projection like:
public interface RequestJoinRunProjection {
int getId();
LocalDate getRequestTime();
String getMessage();
String getRequestDay();
Long getHowLongAgo();
}
Then you define a method on your Repository that has the native query you want to run:
public interface TestRequestRepository extends CrudRepository<TestRequest, Long> {
// Any other custom method for TestRequest entity
#Query(value = "SELECT trq.Id AS id " +
" , trq.RequestTime AS requestTime " +
" , DAYNAME(trq.RequestTime) AS requestDay " +
" , trq.StatusMessage AS statusMessage " +
" , DATEDIFF(YEAR, CURDATE(), trq.RequestTime) AS howLongAgo " +
"FROM TestRequest trq " +
" LEFT JOIN TestRun tr " +
" ON trq.TestRunId = tr.Id " +
"WHERE Requestor = ?1 ORDER BY Id DESC"), nativeQuery = true)
List<RequestJoinRunProjection> findTestSumary(String name);
}
Notice query must be native since you are using database functions, also the column names must match the setters of your projection interface(following bean rules), so use AS in order to change the names in your query.
I strongly suggest you test your query on h2 before injecting into #Query annotation. DATEDIFF requires 3 parameters.
Not able to use custom POJO classes for my spring data jpa queries. Repeatedly fails with the following exception
"org.hibernate.MappingException: Unknown entity:
com.app.mycompany.AgileCenterServices.entities.ComponentDetailedInfo"*
Tried replacing the custom ComponentDetailedInfo.class and not mentioning anything during the call to entityManager.createNativeQuery(componentQuery.toString()), but then Object List returned fails to be converted to the specific POJO class after the query.
#Override
public ComponentListResponsePaginated findComponentByProjectId(String projectId, Pageable pageable) {
logger.info(" Inside findComponentByProjectId() API in IssueComponentServiceImpl");
String componentQuery = "select c.*, u.fullname "
+ "from issue_component c "
+ "left join user u on c.component_lead = u.username "
+ "where "
+ "upper(c.project_id) = upper(" + projectId + ")";
List<ComponentDetailedInfo> compList = new ArrayList<ComponentDetailedInfo>();
try {
logger.info(" ************* Printing query ******************************* ");
logger.info(componentQuery.toString());
compList = entityManager.createNativeQuery(componentQuery.toString(), ComponentDetailedInfo.class) .setFirstResult(pageable.getOffset())
.setMaxResults(pageable.getPageSize())
.getResultList();
}
}
Also tried the following
List<? extends Object> objList = null;
objList = entityManager.createNativeQuery(componentQuery.toString()) .setFirstResult(pageable.getOffset())
.setMaxResults(pageable.getPageSize())
.getResultList();
if(objList != null && objList.size() > 0) {
for(Object rec: objList) {
logger.info(" Printing Object ::: " + rec.toString());
compList.add((ComponentDetailedInfo)rec);
}
}
However the compList fails with the
java.lang.ClassCastException
The custom query returned should get typecast to the specific class type passed to the entityManager.createNativeQuery. However, I am facing the exception as mentioned above when I pass the class to createNativeQuery().
Even tried by totally removed the class in the createNativeQuery...
You have to define a constructor result mapping if you want to use a POJO as a result of a native query.
Here is an example query:
Query q = em.createNativeQuery(
"SELECT c.id, c.name, COUNT(o) as orderCount, AVG(o.price) AS avgOrder " +
"FROM Customer c " +
"JOIN Orders o ON o.cid = c.id " +
"GROUP BY c.id, c.name",
"CustomerDetailsResult");
And that's the mapping you have to add to your Entity:
#SqlResultSetMapping(name="CustomerDetailsResult",
classes={
#ConstructorResult(targetClass=com.acme.CustomerDetails.class,
columns={
#ColumnResult(name="id"),
#ColumnResult(name="name"),
#ColumnResult(name="orderCount"),
#ColumnResult(name="avgOrder", type=Double.class)})
})
If you don't like that approach you could use QLRM. Learn more about it here: https://github.com/simasch/qlrm
I would like to retrieve the first object containing at least one of the given tags in parameter.
#Query("#{#n1ql.selectEntity} WHERE SOME t IN tags SATISFIES t IN [\"#{#currentTags}\"] " +
"END AND #{#n1ql.filter} LIMIT 1")
RecipeEntry findFirstContainingTags(#Param("currentTags")List<String> tags);
But the generated N1QL query is
"SELECT * FROM contents WHERE SOME t IN tags SATISFIES t IN ["tag1,tag2"] END LIMIT 1"
The query expected is
"SELECT * FROM contents WHERE SOME t IN tags SATISFIES t IN ["tag1","tag2"] END LIMIT 1"
So i expect that my parameter currentTags will be converted into ["tag1","tag2"] not ["tag1,tag2"]
Is there a mean to generate this query with Spring data ?
For information, below what i have done :
I use jackson objectMapper to convert my list of String to a json
Give the json as parameter
Service :
public RecipeEntry findMostRecentWithAtLeastTags(List<String> tags) {
RecipeEntry recipeEntry = null;
try {
String tagsArray = objectMapper.writeValueAsString(tags);
recipeEntry = ((RecipeQueryRepository) this.queryRepository).findMostRecentWithAtLeastTags(tagsArray);
} catch (Exception e) {
log.error("Error while retrieving most recent recipe with given tags", e);
}
return recipeEntry;
}
Repository :
#Query("#{#n1ql.selectEntity} WHERE status = 'PUBLISHED' AND (EVERY t IN #{#currentTags} SATISFIES t IN tags END) " +
"AND #{#n1ql.filter} ORDER BY publishDate DESC LIMIT 1")
RecipeEntry findMostRecentWithAtLeastTags(#Param("currentTags") String tags);
I am using Sitecore 7.1 . I used one field Type "Name Lookup value List" . I want catch name/value stored in that Field Type in Code behind in MVC . How can I catch the Key value Item .
string keyValueRawValue = item["NameValueListFieldName"];
NameValueCollection nameValueCollection = Sitecore.Web.WebUtil.ParseUrlParameters(keyValueRawValue );
foreach (string key in nameValueCollection )
{
var value = nv[key];
}