I have a write converter as
public class CarConverter implements Converter<Car, DBObject> {
#Override
public final DBObject convert(final Car car) {
DBObject dbo = new BasicDBObject();
dbo.put("_id", car.getId());
// below line produces error
dbo.put("wheels", car.getWheels());
return dbo;
}
}
and my Car.java as
#Document(collection = "car")
public class Car implements Serializable {
private static final long serialVersionUID = 6121244806685144430L;
#Id private String id;
private List<Wheel> wheels;
// getters and setters
}
and my Wheel.java as (It is not document , just a bean)
public class Wheel implements Serializable {
private static final long serialVersionUID = 6121244806685144430L;
private String wheelId;
private String name;
//getters and setters
}
I got the below error when I try to save my Car object to mongodb.
SLF4J: Failed toString() invocation on an object of type [com.mongodb.BasicDBObject]
java.lang.RuntimeException: json can't serialize type : class com.mypackage.Wheel
at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:77)
at com.mongodb.util.JSONSerializers$IterableSerializer.serialize(JSONSerializers.java:290)
at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79)
at com.mongodb.util.JSONSerializers$MapSerializer.serialize(JSONSerializers.java:317)
at com.mongodb.util.ClassMapBasedObjectSerializer.serialize(ClassMapBasedObjectSerializer.java:79)
at com.mongodb.util.JSON.serialize(JSON.java:55)
at com.mongodb.util.JSON.serialize(JSON.java:40)
at com.mongodb.BasicDBObject.toString(BasicDBObject.java:83)
at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:276)
at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:248)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:206)
at org.slf4j.helpers.MessageFormatter.format(MessageFormatter.java:148)
at org.slf4j.impl.Log4jLoggerAdapter.info(Log4jLoggerAdapter.java:341)
INFO : org.springframework.data.mongodb.core.mapping.event.LoggingEventListener - onBeforeSave:
com.mypackage.Car#1e4ec58, [FAILED toString()]
java.lang.IllegalArgumentException: can't serialize class com.mypackage.Wheel
at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:284)
at org.bson.BasicBSONEncoder.putIterable(BasicBSONEncoder.java:309)
at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:248)
at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:185)
at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:131)
at com.mongodb.DefaultDBEncoder.writeObject(DefaultDBEncoder.java:33)
at com.mongodb.OutMessage.putObject(OutMessage.java:289)
at com.mongodb.OutMessage.writeUpdate(OutMessage.java:180)
at com.mongodb.OutMessage.update(OutMessage.java:60)
at com.mongodb.DBCollectionImpl.update(DBCollectionImpl.java:275)
at com.mongodb.DBCollection.update(DBCollection.java:191)
at com.mongodb.DBCollection.save(DBCollection.java:975)
at com.mongodb.DBCollection.save(DBCollection.java:934)
Please somebody help me , what is the problem ? How can I fix it ?
I ran into this same error. My Document looked like this:
#Document
public class AnalyticsDailyData implements Serializable {
private static final long serialVersionUID = -5409790992784008124L;
#Id
#NotNull
#Valid
private AnalyticsMetaData metaData;
...
Adding an actual id field of type ObjectId made the error go away for me. I then set the metaData field to be indexed and unique.
#Document
public class AnalyticsDailyData implements Serializable {
private static final long serialVersionUID = -5409790992784008124L;
private ObjectId id;
#Indexed(unique = true)
#NotNull
#Valid
private AnalyticsMetaData metaData;
...
I am still able to query by metaData after adding a method to my Repo:
public interface AnalyticsDailyDataRepo extends PagingAndSortingRepository<AnalyticsDailyData, ObjectId> {
AnalyticsDailyData findOneByMetaData(AnalyticsMetaData meta);
}
Related
Overview
I've got an #Entity with an #EmbeddedId composite key. The entities are exposed over a REST api which uses a BackendIdConverter to convert the id string back to an instance of the #Embeddable composite key. My understanding is that this is then used to identify an instance of the #Entity, but that isn't happening.
Question
How is the #Embeddable composite key resolved back to an #Entity?
Code
#Entity
public class MyEntity {
#EmbeddedId
private MyEntityIdentifier id;
#Embeddable
public class MyEntityIdentifier implements Serializable {
public static final String COMPOSITE_KEY_DELIMITER = "_#_";
#Column
private String idPartOne;
#Column
#Temporal(TemporalType.DATE)
private Date idPartTwo;
#Component
public class StringToMyEntityIdentifierConverter implements BackendIdConverter {
#Override
public Serializable fromRequestId(String id, Class<?> aClass) {
String[] split = id.split(COMPOSITE_KEY_DELIMITER);
String idPartOne = split[0];
Date idPartTwo = Date.valueOf(split[1]);
return new MyEntityIdentifier(fullName, lastUpdated);
}
public interface MyEntityRepository extends JpaRepository<MyEntity, MyEntityIdentifier> {
}
I'm not able to get the total count of my query.
JPAQuery query = super.prepareJPAQuery(userAccountHasWorkgroup).where(
userAccountHasWorkgroup.workgroup.id.eq(workgroupId);
query.count();
userAccountHasWorkgrouphas an #Embeddable class as ID.
javax.ejb.EJBTransactionRolledbackException: org.hibernate.exception.DataException: Operand should contain 1 column(s)
I add more information:
#Entity
#Table(name = "UserAccount_has_Workgroup")
public class UserAccountHasWorkgroup implements java.io.Serializable {
private static final long serialVersionUID = 6537213525312531347L;
private UserAccountHasWorkgroupId id;
private UserAccount userAccountByUserAccountId;
private Privilege privilege;
private UserAccount userAccountByApprovedByUserAccountId;
private Workgroup workgroup;
private boolean approved;
private boolean lastActiveWorkgroup;
private boolean isWorkgroupReferent;
...
}
#Embeddable
public class UserAccountHasWorkgroupId implements java.io.Serializable {
private static final long serialVersionUID = 6368469866573301127L;
private long userAccountId;
private long workgroupId;
...
}
If i do:
List<UserAccountHasWorkgroup> result = query.list(userAccountHasWorkgroup);
it works, but when I try to count:
Long count = query.count();
I receive the DataException
Instead of:
query.count();
I do
query.uniqueResult(Wildcard.count.as("count"));
It seems to work properly.
I'm having an issue performing a custom query through the use of a spring data jpa repository.
I have a repository class implementing JPARepository<>. Everything works as expected for all of the built-in CRUD queries along with some custom queries, but doing qualification among inner collections isn't working and is returning back a full result set as though the qualification of the collection did not exist.
For example, here is a query:
public interface MessageRepository extends JpaRepository<Message, Integer> {
#Query("SELECT a FROM Message a, Message_Topic b WHERE a.systemNm = :theSystem AND a. applicationNm = :theApplication AND b.topicNm = :theTopicName AND a.insertTs BETWEEN :theStartDate AND :theEndDate AND a.expirationDt > CURRENT_TIMESTAMP")
List<Message> findMessagesByTopic(#Param("theSystem") String theSystem,
#Param("theApplication") String theApplication,
#Param("theTopicName") String theTopicName,
#Param("theStartDate") Date theStartDate,
#Param("theEndDate") Date theEndDate);
With the following JPA entities:
Message:
#Entity
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="message_id")
private int messageId;
#Column(name="application_nm")
private String applicationNm;
#Column(name="execution_instance_txt")
private String executionInstanceTxt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="expiration_dt")
private Date expirationDt;
#Column(name="grouping_des")
private String groupingDes;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="insert_ts")
private Date insertTs;
#Column(name="message_detail_txt")
private String messageDetailTxt;
#Column(name="message_summary_txt")
private String messageSummaryTxt;
#Column(name="severity_des")
private String severityDes;
#Column(name="system_nm")
private String systemNm;
//uni-directional many-to-one association to Message_Topic
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn(name="message_id", referencedColumnName="message_id")
private Set<Message_Topic> messageTopics;
Message_Topic:
#Entity
public class Message_Topic implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="message_topic_id")
private int messageTopicId;
#Column(name="message_id", insertable=false, updatable=false)
private int messageId;
#Column(name="topic_nm")
private String topicNm;
#Column(name="topic_value_txt")
private String topicValueTxt;
This is your query:
SELECT a FROM Message a, Message_Topic b WHERE a.systemNm = :theSystem AND a. applicationNm = :theApplication AND b.topicNm = :theTopicName AND a.insertTs BETWEEN :theStartDate AND :theEndDate AND a.expirationDt > CURRENT_TIMESTAMP
Where are Message and Message_Topic joined?, If you transform this query to a native query, is possible you can detect the fault.
Actually, I am trying to save one node with RelationshipEntity class as follows:
Node Class
#NodeEntity
public class MyEvent
{
#GraphId
private Long nodeId;
#RelatedToVia(type = "INVITED_TO")
#Fetch Set<EventResponse> eventResponse;
}
RelationshipEntity Class
#RelationshipEntity(type="INVITED_TO")
public class EventResponse implements Serializable
{
#GraphId
Long nodeId;
#StartNode
MyEvent event;
#EndNode
User user;
// .....
}
When I am trying to save MyEvent
org.neo4j.graphdb.NotFoundException: '__type__' property not found for RelationshipImpl #153 of type 15 between Node[159] and Node[117].
So I guess based on above exception, it missing somewhere __type__ property which is required to identify any node type. I am not exactly getting, is there any way that we save first relationship entity followed by NodeEntity or viceversa or simultaneously ??
The type property does not need to be set explicitly by you. It is managed by spring-data-neo4j.
The following code snippets work for me:
The event class:
#NodeEntity
public class MyEvent
{
#GraphId
private Long nodeId;
#RelatedToVia(type = "INVITED_TO")
#Fetch
Set<EventResponse> eventResponse;
}
The user class:
#NodeEntity
public class User
{
#GraphId
private Long userId;
}
And the response class:
#RelationshipEntity(type = "INVITED_TO")
public class EventResponse
{
#GraphId
private Long nodeId;
#StartNode
MyEvent event;
#EndNode
User user;
}
I use them in a short junit test:
#Autowired
private Neo4jTemplate template;
#Transactional
#Test
public void saveEvent()
{
User user = new User();
MyEvent event = new MyEvent();
EventResponse response = new EventResponse();
response.user = user;
response.event = event;
this.template.save(user);
this.template.save(event);
this.template.save(response);
}
I am trying out some very basic webservice. I get this exception everytime I try to return the Prtnr object.
Uncaught exception thrown in one of the service methods of the servlet: spitter. Exception thrown :
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
(through reference chain: org.hibernate.collection.PersistentSet[0]->org.abc.dvo.PrtnrGeoInfo["id"]->org.abc.dvo.PrtnrGeoInfoId["partner"]->
org.abc.dvo.Prtnr["prtnrGeoInfos"]->org.hibernate.collection.PersistentSet[0]->org.abc.dvo.PrtnrGeoInfo["id"]->org.abc.dvo.PrtnrGeoInfoId["partner"]->
org.abc.dvo.Prtnr["prtnrGeoInfos"]->org.hibernate.collection.PersistentSet[0]->org.abc.dvo.PrtnrGeoInfo["id"]->org.abc.dvo.PrtnrGeoInfoId["partner"]->
org.abc.dvo.Prtnr["prtnrGeoInfos"]->org.hibernate.collection.PersistentSet[0]->org.abc.dvo.PrtnrGeoInfo["id"]->org.abc.dvo.PrtnrGeoInfoId["partner"]->
...
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:164)
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
...
The Prtnr class is :
public class Prtnr implements Cloneable, java.io.Serializable {
private static final long serialVersionUID = 201207021420600052L;
private Integer prtnrId;
private String creatUserId;
private Date creatTs;
private String updtUserId;
private Date updtTs;
private String prtnrNm;
private Integer cncilNum;
private Character prtnrTypCd;
private Set<PrtnrGeoInfo> prtnrGeoInfos = new HashSet<PrtnrGeoInfo>(0);
private Set<PrtnrDtl> prtnrDtls = new HashSet<PrtnrDtl>(0);
private Set<SuplyDtl> suplyDtls = new HashSet<SuplyDtl>(0);
private Set<TrnsprtDtl> trnsprtDtls = new HashSet<TrnsprtDtl>(0);
private Set<PrtnrFacil> prtnrFacils = new HashSet<PrtnrFacil>(0);
private Set<PrtnrHumanResrc> prtnrHumanResrcs = new HashSet<PrtnrHumanResrc>(0);
.....
.....
Getters and setters for these properties
...
}
The PrtnrGeoInfo class is :
public class PrtnrGeoInfo implements java.io.Serializable {
private PrtnrGeoInfoId id = new PrtnrGeoInfoId();
private String creatUserId;
private Date creatTs;
private String updtUserId;
private Date updtTs;
Getters and setters for these properties
}
The PrtnrGeoInfoId class is :
public class PrtnrGeoInfoId implements java.io.Serializable {
private Prtnr partner;
private GeoSegment geoSegment;
private static final long serialVersionUID = 201207060857580050L;
Getters and setters for these properties
}
I believe it is because of the classes refrencing each other. But how can this problem be resolved. Within the app which is Struts 2 and Spring, this object get passed just fine.
The controller class is as follows:
#Controller
#RequestMapping("/partners")
public class PartnerController {
#RequestMapping(value="/{id}", method=RequestMethod.GET, headers ={"Accept=text/xml,application/json"})
#ResponseBody
public Prtnr getPartner(#PathVariable("id") String id) throws Exception{
Prtnr partner = null;
try{
partner = partnerService.getPartnerById(Integer.valueOf(id));
System.out.println("******* Test message " );
}catch(Exception ex){
System.out.println("******* Exception thrown ... " + ex.getMessage());
}
return partner;
}
}
The calling class is
public class TestTemplate
{
private static final long serialVersionUID = 1130201273334264152L;
public static void main(String[] args){
Prtnr partner = (Prtnr)new RestTemplate().getForObject("http://localhost:9080/respondersApp/testWs/partners/{id}", Prtnr.class, "1");
System.out.println("partner name is : " + partner.getPrtnrNm());
}
}
In this link you can find how to solve this.
However below I'll paste the solution in practice.
It's very simple. Assuming that your database query already works without JSON, all you have to do is this:
Add the #JsonManagedReference In the forward part of the relationship (i.e. User.java class):
#Entity
public class User implements java.io.Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
#Column(name="name")
private String name;
#ManyToMany
#JoinTable(name="users_roles",joinColumns=#JoinColumn(name = "user_fk"),
inverseJoinColumns=#JoinColumn(name = "role_fk"))
#JsonManagedReference
private Set<Role> roles = new HashSet<Role>();
...
Add the #JsonBackReference In the back part of the relationship (i.e. Role.java class):
#Entity
public class Role implements java.io.Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#ManyToMany(mappedBy="roles")
#JsonBackReference
private Set<User> users = new HashSet<User>();
...
The work is done. If you take a look at your firebug logs, you'll notice that the infinite recursive loop has disappeared.
This is quite a common scenario for me when you are trying to convert entity classes into JSON format. The simplest solution is just to use #JsonIgnore on the reverse mapping to break the cycle.
You can annotate the second reference of Prtnr in PrtnrGeoInfoId with #JsonBackReference
The infinite recursion is due to the following:
Class Prtnr contains Set<PrtnrGeoInfo> prtnrGeoInfos and each PrtnrGeoInfo contains PrtnrGeoInfoId id which in turn contains Prtnr partner.
Thus, Prtnr -> PrtnrGeoInfo ->PrtnrGeoInfoId ->Prtnr, is causing a cyclic dependency which is a problem for Jackson when it is trying to do the POJO Mapping.
You need to remove this cyclic dependency to fix this exception.