I have the following CriteriaQuery that I use to filter orders.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<OrderReducedDTO> cq = cb.createQuery(OrderReducedDTO.class);
Root<Order> root = cq.from(Order.class);
Join<Order, Customer> joinCustomer = root.join(Order_.customer);
Join<Order, Shipment> joinShipment = root.join(Order_.shipment);
Join<Shipment, Carrier> joinCarrier = joinShipment.join(Shipment_.carrier);
Join<Order, Payment> joinPayment = root.join(Order_.payment);
Join<Payment, PaymentMethod> joinPaymentMethod = joinPayment.join(Payment_.paymentMethod);
Join<Shipment, Country> joinCountry = joinShipment.join(Shipment_.country);
cq.select(cb.construct(
OrderReducedDTO.class,
root.get(Order_.id),
root.get(Order_.incrementId),
root.get(Order_.state),
root.get(Order_.couponCode),
root.get(Order_.totalDiscount),
root.get(Order_.total),
root.get(Order_.originChannel),
root.get(Order_.branchOffice),
joinCarrier.get(Carrier_.carrierCode),
cb.function("CONCAT_WS", String.class,
cb.literal(","),
joinShipment.get(Shipment_.streetName),
joinShipment.get(Shipment_.streetNumber),
joinShipment.get(Shipment_.city),
joinCountry.get(Country_.name),
joinShipment.get(Shipment_.zipCode)
),
joinPaymentMethod.get(PaymentMethod_.code),
joinPayment.get(Payment_.paymentDate),
root.get(Order_.createdAt),
root.get(Order_.updatedAt),
root.get(Order_.externalId),
joinCustomer.get(Customer_.fullName)
));
... filters and predicates...
The part that's giving me trouble and causing a NPE to be thrown is this
cb.function("CONCAT_WS", String.class,
cb.literal(","),
joinShipment.get(Shipment_.streetName),
joinShipment.get(Shipment_.streetNumber),
joinShipment.get(Shipment_.city),
joinCountry.get(Country_.name),
joinShipment.get(Shipment_.zipCode)
)
More, specifically, when I use the CONCAT_WS function. If I use CONCAT, it works.
This is the stacktrace I get:
java.lang.NullPointerException: null
at org.hibernate.hql.internal.NameGenerator.generateColumnNames(NameGenerator.java:27)
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.generateColumnNames(SessionFactoryHelper.java:434)
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeColumnNames(SelectClause.java:270)
at org.hibernate.hql.internal.ast.tree.SelectClause.finishInitialization(SelectClause.java:260)
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:255)
at org.hibernate.hql.internal.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:1026)
...
This is my OrderReducedDTO
#Getter
public class OrderReducedDTO {
#JsonProperty("order_id")
private Integer orderId;
#JsonProperty("increment_id")
private String incrementId;
private OrderStates state;
#JsonProperty("coupon_code")
private String couponCode;
#JsonProperty("total_discount")
private BigDecimal totalDiscount;
private BigDecimal total;
#JsonProperty("origin_channel")
private String originChannel;
#JsonProperty("branch_office")
private String branchOffice;
#JsonProperty("shipping_method")
private String shippingMethod;
#JsonProperty("shipping_address")
private String shippingAddress;
#JsonProperty("payment_method")
private String paymentMethod;
#JsonProperty("payment_date")
private Timestamp paymentDate;
#JsonProperty("created_at")
private Timestamp createdAt;
#JsonProperty("updated_at")
private Timestamp updatedAt;
#JsonProperty("external_id")
private String externalId;
#JsonProperty("customer_full_name")
private String customerFullName;
#Setter
private List<OrderProductReducedDTO> products;
public OrderReducedDTO(Integer orderId,
String incrementId,
OrderStates state,
String couponCode,
BigDecimal totalDiscount,
BigDecimal total,
String originChannel,
String branchOffice,
String shippingMethod,
String shippingAddress,
String paymentMethod,
Object paymentDate,
Object createdAt,
Object updatedAt,
String externalId,
String customerFullName) {
this.orderId = orderId;
this.incrementId = incrementId;
this.state = state;
this.couponCode = couponCode;
this.totalDiscount = totalDiscount;
this.total = total;
this.originChannel = originChannel;
this.branchOffice = branchOffice;
this.shippingMethod = shippingMethod;
this.shippingAddress = shippingAddress;
this.paymentMethod = paymentMethod;
this.paymentDate = (Timestamp) paymentDate;
this.createdAt = (Timestamp) createdAt; //https://hibernate.atlassian.net/browse/HHH-4179
this.updatedAt = (Timestamp) updatedAt;
this.externalId = externalId;
this.customerFullName = customerFullName;
}
}
What I mainly want to know is if I'm using the function method correctly. I assume I am because CONCAT works.
After hours of debugging within Hibernate, I finally arrived at the root of the problem:
org/hibernate/hql/internal/ast/tree/ConstructorNode.java
private Type[] resolveConstructorArgumentTypes() throws SemanticException {
SelectExpression[] argumentExpressions = this.collectSelectExpressions();
if (argumentExpressions == null) {
return new Type[0];
} else {
Type[] types = new Type[argumentExpressions.length];
for(int x = 0; x < argumentExpressions.length; ++x) {
types[x] = argumentExpressions[x].getDataType();
}
return types;
}
}
argumentExpressions[x].getDataType() was returning null.
I googled and found out that this could be caused by Hibernate not knowing the actual return type of the given SQL function (apparently it only knows the most common ones).
I then followed this answer and implemented a custom MetadataBuilderContributor like so:
public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
#Override
public void contribute(MetadataBuilder metadataBuilder) {
metadataBuilder.applySqlFunction(
"concat_ws",
new StandardSQLFunction("concat_ws", StandardBasicTypes.STRING)
);
}
}
And on my application.properties I added:
spring.jpa.properties.hibernate.metadata_builder_contributor=ar.com.glamit.glamitoms.config.hibernate.SqlFunctionsMetadataBuilderContributor
After relaunching the app, argumentExpressions[x].getDataType() now returns a StringType and the NullPointerException is gone.
Related
I am using hibernate to save data to my table.
I have my entity class and main class, through main class i have called the entity class constructor and build the object and in a for loop saving the object to DB through hibernate. I am getting OutofMemory Error : GC overhead limit exceeded, I dont understand why, Can anyone please help?
OutOfMemoryError
Here's my code :
Session session = HibernateSessionFactory.getSession();
for(int i=0;i<serviceIds.length;i=i++)
{
EntityClass ec = new EntityClass
(Integer.parseInt(serviceIds[i]),0,someId3, 0,1,id2,
new Timestamp(System.currentTimeMillis()), 0,
null, null, 0, null,null,null,null);
session.save(ec);
}
session.flush();
session.clear();
Here's my entity class:
public class EntityClass implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer someId1;
private Integer someId2;
private Integer someId3;
private Integer flag1;
private Integer flag2;
private Integer createdBy;
private Timestamp createdDate;
private Integer modifiedBy;
private Timestamp modifiedDate;
private Timestamp endDate;
private Integer attribute1;
private String attribute2;
private String attribute3;
private String attribute4;
private String attribute5;
//full constructor
public EntityClass(Integer someId1, Integer someId2,
Integer someId3, Integer funBlockFlag, Integer functionalFlag,
Integer createdBy, Timestamp createdDate, Integer modifiedBy,
Timestamp modifiedDate, Timestamp endDate, Integer attribute1,
String attribute2, String attribute3, String attribute4,
String attribute5) {
this.someId1= someId1;
this.someId2 = someId2;
this.someId3 = someId3;
this.funBlockFlag = funBlockFlag;
this.functionalFlag = functionalFlag;
this.createdBy = createdBy;
this.createdDate = createdDate;
this.modifiedBy = modifiedBy;
this.modifiedDate = modifiedDate;
this.endDate = endDate;
this.attribute1 = attribute1;
this.attribute2 = attribute2;
this.attribute3 = attribute3;
this.attribute4 = attribute4;
this.attribute5 = attribute5;
}
//getter and setters of all fields
Can anyone help me with the issue?
When we persist an entity (in this case EntityClass), Hibernate will store it in the persistence context.
From your case, it seem like the length for serviceIds might be too large with the memory that you set for your JVM.
Perhaps try to flush and clear the persistence context for every N elements. For example, let said your BATCH_SIZE is 20
private static final BATCH_SIZE = 20; // declare at class level
Session session = HibernateSessionFactory.getSession();
for(int i=0;i<serviceIds.length;i=i++)
{
EntityClass ec = new EntityClass
(Integer.parseInt(serviceIds[i]),0,someId3, 0,1,id2,
new Timestamp(System.currentTimeMillis()), 0,
null, null, 0, null,null,null,null);
session.save(ec);
if (i % BATCH_SIZE == 0) {
session.flush();
session.clear();
}
}
session.flush();
session.clear();
I'm trying to convert the following Mongo query for use with Spring data.
db.product.aggregate([
{$unwind: '$barcodes'},
{$project: {
_id: 0,
productId: '$_id',
productTitle: '$title',
productVariation: '$variation',
barcode: '$barcodes'
}}])
This is what I've been trying so far. It returns the aggregation, but with null values:
UnwindOperation unwindOperation = Aggregation.unwind("barcodes");
ProjectionOperation projectStage = Aggregation.project().and("productId").as("_id").and("productTitle")
.as("title")
.and("productVariation").as("variation")
.and("barcodeTitle").as("barcodes.title")
.and("barcodeValue").as("barcodes.value")
.and("barcodeType").as("barcodes.type")
.and("codeStandard").as("barcodes.codeStandard")
.and("quantity").as("barcodes.quantity")
.and("status").as("barcodes.status");
SortOperation sortOperation = Aggregation.sort(Sort.by(Sort.Direction.DESC, "title"));
Aggregation agg = Aggregation.newAggregation(unwindOperation, projectStage, sortOperation);
AggregationResults<BarcodeAggregateList> results = mongoTemplate.aggregate(agg, "product", BarcodeAggregateList.class);
What it is returning:
The class I am mapping to (has getters/setters):
public class BarcodeAggregateList {
private String productId;
private String productTitle;
private String productVariation;
private String barcodeTitle;
private String barcodeValue;
private String barcodeType;
private String codeStandard;
private int quantity;
private String status;
}
Product class that the data is coming from:
public class Product implements Serializable {
private static final long serialVersionUID = -998149317494604215L;
private String id;
private String title;
private String description;
private String SKU;
private double cost;
private double retailPrice;
private String status;
private LocalDate launchDate;
private LocalDate discontinueDate;
private String discontinueReason;
private String salesChannel;
private List<Barcode> barcodes;
private ProductVariation variation;
private List<Supplier> supplier;
private Product parentProduct;
private boolean updateChildren;
private Label label;
private int secondaryStockLevel;
private int primaryStockLevel;
private Date createdDate;
private Date modifiedDate;
private List<Dimension> dimensions;
private boolean isDeleted = false;
}
Barcode class
public class Barcode {
private String type;
private String title;
private String value;
private String status;
private String codeStandard;
private int quantity;
}
I appreciate any help with this or resources to help me better understand how to perform these types of conversions.
For anyone trying to solve similar issues, I've found the following resources somewhat helpful:
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.query
https://xpadro.com/2016/04/data-aggregation-with-spring-data-mongodb-and-spring-boot.html
https://www.tutorialspoint.com/get-fields-from-multiple-sub-documents-that-match-a-condition-in-mongodb
BarcodeAggregateList class fields are null because there is a minor issue in ProjectionOperation's and() and as() methods. The correct syntax is
Aggregation.project().and(SOURCE_FIELD).as(TARGET_FIELD)
You have written and("productId").as("_id") , which is wrong
You need to write this as and("_id").as("productId") , because source field is _id
complete code:
UnwindOperation unwindOperation = Aggregation.unwind("barcodes");
ProjectionOperation projectStage = Aggregation.project()
.and("_id").as("productId")
.and("title").as("productTitle")
.and("variation").as("productVariation")
.and("barcodes.title").as("barcodeTitle")
.and("barcodes.value").as("barcodeValue")
.and("barcodes.type").as("barcodeType")
.and("barcodes.codeStandard").as("codeStandard")
.and("barcodes.quantity").as("quantity")
.and("barcodes.status").as("status");
SortOperation sortOperation = Aggregation.sort(Sort.by(Sort.Direction.DESC, "productTitle"));
Aggregation agg = Aggregation.newAggregation(unwindOperation, projectStage, sortOperation);
AggregationResults<BarcodeAggregateList> results = mongoTemplate.aggregate(agg, "product", BarcodeAggregateList.class);
I try select data from the table by a filter with Spring Data JPA Specification I think what my implementation is correct, But it doesn't work. Help me please understand my mistake and fix my example.
I have very strange SQL query in log :
select phone0_.id as id1_0_, phone0_.note as note2_0_, phone0_.number as number3_0_, phone0_.operator_login as operator4_0_, phone0_.operator_pass as operator5_0_, phone0_.operator_name as operator6_0_, phone0_.operator_url as operator7_0_, phone0_.reg_date as reg_date8_0_, phone0_.status as status9_0_ from phone phone0_ where 0=1 limit ?
In the end: where 0=1 it's crash my mind. Where did that come from?
Here I fill CriteriaBuilder if filter field not null. I expect to get correctly built Specification object and send it to findAll(Specifications.where(specification), Pageable p) method. But something incorrect.
My repo and specification impl:
public interface PhoneRepository extends CrudRepository<Phone, Integer>, JpaRepository<Phone, Integer>, JpaSpecificationExecutor<Phone> {
class PhoneSpecification implements Specification<Phone> {
private final #NonNull PhoneService.PhoneFilter filter;
public PhoneSpecification(#NonNull PhoneService.PhoneFilter filter) {
this.filter = filter;
}
#Override
public Predicate toPredicate(Root<Phone> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.disjunction();
if (nonNull(filter.getId())) {
cb.disjunction().getExpressions().add(cb.equal(root.get("id"), filter.getId()));
}
if (nonNull(filter.getNote())) {
cb.disjunction().getExpressions().add(cb.like(root.get("note"), filter.getNote()));
}
if (nonNull(filter.getNumber())) {
cb.disjunction().getExpressions().add(cb.like(root.get("number"), filter.getNumber()));
}
if (nonNull(filter.getStatus())) {
cb.disjunction().getExpressions().add(cb.like(root.get("status"), filter.getStatus()));
}
if (nonNull(filter.getOpName())) {
cb.disjunction().getExpressions().add(cb.like(root.get("operatorName"), filter.getOpName()));
}
if (nonNull(filter.getOpLogin())) {
cb.disjunction().getExpressions().add(cb.like(root.get("operatorAccLogin"), filter.getOpLogin()));
}
if (nonNull(filter.getOpPassword())) {
cb.disjunction().getExpressions().add(cb.like(root.get("operatorAccPassword"), filter.getOpPassword()));
}
if (nonNull(filter.getRegFrom()) && nonNull(filter.getRegTo())) {
cb.disjunction().getExpressions().add(cb.between(root.get("regDate"), filter.getRegFrom(), filter.getRegTo()));
}
return predicate;
}
}
}
This is service level:
#Service
public class PhoneService {
#Autowired
private PhoneRepository phoneRepository;
public Phone get(int id) {
Phone phone = phoneRepository.findOne(id);
return nonNull(phone) ? phone : new Phone();
}
public Page<Phone> list(#NonNull PhoneFilter filter) {
PhoneSpecification specification = new PhoneSpecification(filter);
return phoneRepository.findAll(Specifications.where(specification), filter.getPageable());
}
#Data
public static class PhoneFilter {
private Pageable pageable;
private Integer id;
private Timestamp regFrom;
private Timestamp regTo;
private String number;
private String opLogin;
private String opPassword;
private String opName;
private String status;
private String note;
}
}
And entity
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "phone")
#ToString(exclude = {"accounts"})
#EqualsAndHashCode(exclude = {"accounts"})
public class Phone {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#OneToMany(mappedBy = "phone", cascade = CascadeType.DETACH)
private Collection<SocialAccount> accounts;
#Column(name = "reg_date")
private Timestamp regDate;
#Column(name = "number")
private String number;
#Column(name = "operator_url")
private String operatorUrl;
#Column(name = "operator_login")
private String operatorAccLogin;
#Column(name = "operator_pass")
private String operatorAccPassword;
#Column(name = "operator_name")
private String operatorName;
#Column(name = "status")
private String status;
#Column(name = "note")
private String note;
}
I find the mistake.
Method CriteriaBuilder.disjunction() this is factory and each time when I call him I got new Predicate object.
This implementation CriteriaBuilderImpl:
public Predicate disjunction() {
return new CompoundPredicate(this, BooleanOperator.OR);
}
Be careful with it.
#DynamoDBTable(tableName = "OrderDashboardMetadata")
public class OrderDashBoardMetaData {
private int position;
private Date ETA = null;
private List<String> notes;
#DynamoDBHashKey(attributeName = "queueName")
private String queueName;
#DynamoDBRangeKey(attributeName = "orderId")
private String orderId;
#DynamoDBIndexHashKey(globalSecondaryIndexName = "city")
private String city;
#DynamoDBIndexRangeKey(globalSecondaryIndexName = "city")
private String fcId;
#DynamoDBIndexHashKey(globalSecondaryIndexName = "orderState")
private String orderState;
#DynamoDBAttribute(attributeName = "action")
private String action;
#DynamoDBAttribute(attributeName = "createdTime")
private Date createdTime = new Date();
#DynamoDBAttribute(attributeName = "updatedTime")
private Date updatedTime = new Date();
Hi
I have a table structure like the one above.
What would be query to fetch results only that have
1) queueName -- > PFS
2) ETA --> greater than 1st jan 2017
3)order state -- PO
Kindly suggest full query for the above scenario in JAVA.
Since you have not annotated so assuming ETA is also an DDBAttribute
Map<String, AttributeValue> expValues = new HashMap<>();
expValues.put(":hv", new AttributeValue("PFS"));
expValues.put(":osv", new AttributeValue("PO"));
expValues.put(":etav", new AttributeValue("2017-01-01"));
QueryRequest q = new QueryRequest("OrderDashboardMetadata");
q.setKeyConditionExpression("queueName = :hv");
q.setFilterExpression("orderState = :osv and ETA > :etav");
q.setExpressionAttributeValues(expValues);
QueryResult r = dbClient.query(q);
Note: Dates are stored as S (string type). The Date values are stored as ISO-8601 formatted strings.
I am developing an application using GeoModel. I need to perform search in a particular radius based on the given latitude and longitude. I am able to generate the GeoCells in the datastore using Objectify, but not able to get back the results in a particular radius.
I am sharing my code below.
Entity Class
#Entity
public class NewsFeed implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Index
private Long feedID;
#Index
private String topic;
#Index
private String title;
private String description;
#Index
private Date createDate;
private String imageOrVideo;
private String imageUrl;
private String blobKey;
#Latitude
private Double latitude;
#Longitude
private Double longitude;
#Geocells
private List<String> cells;
// getter and setters ...
}
Custom GeocellQueryEngine Class From This Source
public class ObjectifyGeocellQueryEngine implements GeocellQueryEngine {
private String geocellsProperty;
private Objectify ofy;
public static final String DEFAULT_GEOCELLS_PROPERTY = "cells";
public ObjectifyGeocellQueryEngine(Objectify ofy) {
this(ofy, DEFAULT_GEOCELLS_PROPERTY);
}
public ObjectifyGeocellQueryEngine(Objectify ofy, String geocellsProperty) {
this.ofy = ofy;
this.geocellsProperty = geocellsProperty;
}
#Override
public <T> List<T> query(GeocellQuery baseQuery, List<String> geocells, Class<T> entityClass) {
StringTokenizer st;
int tokenNo = 0;
Query<T> query = ofy.query(entityClass);
if (baseQuery != null) {
st = new StringTokenizer(baseQuery.getBaseQuery(), ",");
while (st.hasMoreTokens()) {
query.filter(st.nextToken(), baseQuery.getParameters().get(tokenNo++));
}
}
return query.filter(geocellsProperty + " IN", geocells).list();
}
}
Fetching Data Here
Point p = new Point(24.8993714, 79.5839124);
// Generates the list of GeoCells
List<String> cells = GeocellManager.generateGeoCell(p);
List<Object> params = new ArrayList<Object>();
params.add("Movies");
GeocellQuery baseQuery = new GeocellQuery("topic == topic", "String topic",params);
ObjectifyGeocellQueryEngine objectifyGeocellQueryEngine = new ObjectifyGeocellQueryEngine(ofy(), "cells");
List<NewsFeed> list = objectifyGeocellQueryEngine.query(baseQuery, cells, NewsFeed.class);
List<NewsFeed> list2 = GeocellManager.proximitySearch(p, 10, 10000,NewsFeed.class, baseQuery, objectifyGeocellQueryEngine, GeocellManager.MAX_GEOCELL_RESOLUTION);
System.out.println(list+" : "+list2);
Now the problem is I am not getting any results out from here. Can you people please help me with this as I am not getting any exception, just getting the empty list.
I have done a workaround for this situation I have added a parallel JDO Class to store and retrieve the geospatial results.