I'm trying to create a table with a BeanContainer after populating it. However, when I try to run it, I get the following error message:
java.lang.IllegalStateException: Property RoomID not found
The relevant code is below (in which rooms can create a list of random Room objects). The Room class has a RoomID integer, and while it is a private variable the code produces the same error even if RoomID isn't private. I've also made sure that r_list actually contains Room instances.
BeanContainer<Integer, Room> r_cont = new BeanContainer<Integer, Room>(Room.class);
r_cont.setBeanIdProperty("RoomID");
//fetches all rooms and adds them to the bean container
List<Room> r_list = rooms.getRooms();
for (Room room: r_list)
r_cont.addBean(room);
EDIT: Here's the notable part of the Room object. I left out the initialization method and the methods for setting/getting the other variables.
package Entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="Room")
public class Room {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="RoomID")
private int RoomID;
...
public int getRoomID(){
return RoomID;
}
...
}
The property name is not deducted from the the actual variable holding it, but from the getter/setter. This means it should be roomId (see e.g. Where is the JavaBean property naming convention defined?). If you are not sure about the properties you hold, you can debug it on the container with: .getContainerPropertyIds().
Related
I want to use Auth User Table for other Tables. Specificly I want to use the ID for other Tables as Foreign key. It worked fine until I started Implementing OAuth2 into the chanel.dart. Now its thowing an error:
Data Model Error: Relationship 'resourceOwner' on '_ManagedAuthToken' expects that just one 'ManagedObject' subclass uses a table definition that extends 'ResourceOwnerTableDefinition. But the following implementations were found: User,User. That's just how it is for now.
I have no clue how to fix that. And I think it is pretty obvious, that if you have multiple users, with profiles, you should be able to take the userID as an foreign key, to show ownership.
EDIT:
The ManagedObject declarations look like these:
import 'package:lobBook_backend/lobBook_backend.dart';
import 'Book.dart';
import 'User.dart';
class _userBooksLikes extends ManagedObject<_userBooksLikes> implements _userBooksLikes{
}
class _userBooksLikes {
#primaryKey
int id;
#Relate(#usrEvntSts, onDelete: DeleteRule.cascade)
User user;
#Relate(#usrEvntSts, onDelete: DeleteRule.cascade)
Book book;
#Column(indexed: true)
int status;
}
import 'package:lobBook_backend/lobBook_backend.dart';
import '_userBooksLikes.dart';
import 'User.dart';
class Book extends ManagedObject<_Book> implements _Book {}
class _Book {
#primaryKey
int id;
#Column(indexed: true)
String name;
#Column(indexed: true)
DateTime date;
#Relate(#ownedBooks)
User user;
ManagedSet<_userBooksLikes> usrEvntSts;
}
import 'package:aqueduct/managed_auth.dart';
import 'package:lobBook_backend/lobBook_backend.dart';
import 'package:lobBook_backend/model/_userBooksLikes.dart';
import 'Book.dart';
class User extends ManagedObject<_User> implements _User, ManagedAuthResourceOwner<_User> {}
class _User extends ResourceOwnerTableDefinition {
ManagedSet<_userBooksLikes> usrEvntSts;
ManagedSet<Book> ownedBooks;
}
I am trying to create nodes of a specific type with properties which can be dynamic .
For Example : I can create a Person node with name,age,address properties. But these need not be the only properties when I create another Person node. This node can have name,age,address and an additional property salary. Using spring data or query DSL needs me to create Java POJO class Person with fixed number of instance variables name,age and address .
#NodeEntity
public class Person {
#GraphId private Long id;
private String name;
private String age;
private String address;
}
I cannot add a dynamic property for salary for another Person node. Is there a way I can achieve this ?
Dynamic properties are not supported in Neo4j-OGM at the moment (see https://jira.spring.io/browse/DATAGRAPH-555)
If you only interact with your graph via the OGM and do not have to query on individual dynamic properties, you could try a Map of properties with a custom Converter, that converts this Map to a String (like json). The OGM will then use this converter to serialize the map to and from the graph.
Note that because the values are squashed into a String, it is now not trivial to query on an individual dynamic property.
To create a custom converter you need to implement org.neo4j.ogm.typeconversion.AttributeConverter and provide the implementation to convert from a Map to String.
Then, annotate your map property in your domain entity like this:
#Convert(MoneyConverter.class)
Edit:
As pointed out by Michael, if the salary is the only extra optional property, then it makes sense to have this property but set it only when it has a value. Dynamic properties are overkill in this case. You may want to use dynamic properties when you have an unknown and arbitrary set of properties to be persisted with the node
You can workaround the limitations by creating a CompositeAttributeConverter saving each dynamic property in the graph (not only as JSON-String wich cannot be queried well - as mentioned by luanne in the accepted answer)
import java.lang.reflect.Field;
import java.util.*;
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
public abstract class DynamicPropertiesConverter implements CompositeAttributeConverter<Map<String, ?>> {
private Set<String> blacklist;
public DynamicPropertiesConverter(Class<?> clazz) {
blacklist = new HashSet<>();
addAllFields(clazz);
}
public DynamicPropertiesConverter(Set<String> blacklist) {
this.blacklist = blacklist;
}
public void addAllFields(Class<?> type) {
for (Field field : type.getDeclaredFields()) {
blacklist.add(field.getName());
}
if (type.getSuperclass() != null) {
addAllFields(type.getSuperclass());
}
}
#Override
public Map<String, ?> toGraphProperties(Map<String, ?> value) {
Map<String, ?> result = new HashMap<>(value);
result.keySet().removeAll(blacklist);
return result;
}
#Override
public Map<String, ?> toEntityAttribute(Map<String, ?> value) {
return toGraphProperties(value);
}
}
Now you can create a special version of this converter:
public class DynamicNodePropertiesConverter extends DynamicPropertiesConverter {
public DynamicNodePropertiesConverter() {
super(Node.class);
}
}
And use it like this:
import java.util.Map;
import DynamicNodePropertiesConverter;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.typeconversion.Convert;
#NodeEntity
public class Node {
#Convert(DynamicNodePropertiesConverter.class)
private Map<String, Object> data;
/* getter and setter */
}
I have the following domain models:
Route entity:
package org.gmjm.logistics.domain;
import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.annotation.StartNode;
#RelationshipEntity(type="ROUTE")
public class Route
{
#GraphId
private Long routeId;
private Long latencyInMinutes;
#StartNode
private Hub originHub;
#EndNode
private Hub destinationHub;
//Getters & Setters
}
Hub entity:
package org.gmjm.logistics.domain;
import java.util.Collection;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
#NodeEntity
public class Hub
{
#GraphId
private Long nodeId;
private String hubName;
private Long x;
private Long y;
#Relationship(type="ROUTE",direction= Relationship.INCOMING)
private Collection<Route> incomingRoutes;
#Relationship(type="ROUTE",direction=Relationship.OUTGOING)
private Collection<Route> outgoingRoutes;
}
And the following Repositories:
package org.gmjm.logistics.repository;
import org.gmjm.logistics.domain.Hub;
import org.springframework.data.neo4j.repository.GraphRepository;
public interface HubRepository extends GraphRepository<Hub>
{
}
public interface RouteRepository extends GraphRepository<Route>
{
}
Here are the links to the other important files, on Gist to save space:
DemoNeo4jConfig.java
SpringDataNeo4jDemoApplication
build.gradle
I'm running into the following exception, and have tried a lot of different things to get this to work. I've never had an issue with posting relations in this way with spring data rest before.
Posted JSON to http:localhost:8080/routes
{
"latencyInMinutes" : 1500,
"originHub" : "http://localhost:8080/hubs/1044",
"destinationHub" : "http://localhost:8080/hubs/1045"
}
Exception:
{
"cause": {
"cause": null,
"message": "Can not instantiate value of type [simple type, class org.gmjm.logistics.domain.Hub] from String value ('http://localhost:8080/hubs/1044'); no single-String constructor/factory method\n at [Source: HttpInputOverHTTP#207155db; line: 2, column: 30] (through reference chain: org.gmjm.logistics.domain.Route[\"originHub\"])"
},
"message": "Could not read document: Can not instantiate value of type [simple type, class org.gmjm.logistics.domain.Hub] from String value ('http://localhost:8080/hubs/1044'); no single-String constructor/factory method\n at [Source: HttpInputOverHTTP#207155db; line: 2, column: 30] (through reference chain: org.gmjm.logistics.domain.Route[\"originHub\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class org.gmjm.logistics.domain.Hub] from String value ('http://localhost:8080/hubs/1044'); no single-String constructor/factory method\n at [Source: HttpInputOverHTTP#207155db; line: 2, column: 30] (through reference chain: org.gmjm.logistics.domain.Route[\"originHub\"])"
}
(Server Stack)[https://gist.github.com/aglassman/0eb32f371cb2c556543d]
I've tried the obvious, like adding a constructor with a string that was parsed to ID, and one that set hubName, and a few other combination. I'm guessing there is some JSON annotation I can use to fix this, but I can't find anything in the docs. Any ideas?
The following is not working for me when using abstract (or non-abstract for that matter) inheritance in Grails.
Very quickly, my inheritance is as follows:
abstract BaseClass { ... }
SomeClass extends BaseClass { ... }
SomeOtherClass extends BaseClass { ... }
And then in another domain object:
ThirdClass {
...
BaseClass baseProperty
...
}
But now, when I try to set that property to either a SomeClass or SomeOtherClass instance, Grails compains:
ERROR util.JDBCExceptionReporter - Cannot add or update a child row: a foreign key constraint fails
...
Is this not possible?
I have also tried having the base class not be abstract, and also tried casting the SomeClass or SomeOtherClass instances to BaseClass. They generate the same error.
UPDATE
I just checked. It works for the first sub-class that I add. But as soon as I try to add the other sub-class it fails.
In other words:
def prop1 = new ThirdClass(baseProperty: instanceOfSomeClass).save()
works fine. But when I then try and do:
def prop2 = new ThridClass(baseProperty: instanceOfSomeOtherClass).save()
it fails.
UPDATE 2
Further investigation shows that something goes wrong during the table creation process. It correctly adds two foreign keys to the ThirdClass table, but the keys incorrectly references:
CONSTRAINT `...` FOREIGN KEY (`some_id`) REFERENCES `base_class` (`id`),
CONSTRAINT `...` FOREIGN KEY (`some_id`) REFERENCES `some_class` (`id`)
Don't know why it's choosing the base class and one of the sub-classes? I have tried cleaning etc.
First of all, create your BaseClass outside domain structure. It must be an external class, put it on script folder, source folder.
package com.example.model
/**
* #author Inocencio
*/
class BaseClass {
Date createdAt = new Date()
}
Now, create a regular domain class and extend it.
package com.example.domain
import com.example.model.BaseClass
class SomeClass extends BaseClass {
String name
static constraints = {
name(nullable: false)
}
}
As you can see, once you persist SomeClass a createdAt field is filled and saved as well. Check the test class out:
#TestFor(SomeClass)
class SomeClassTests {
void testSomething() {
def some = new SomeClass()
some.name = "Hello There"
some.save()
//find it
def someFind = SomeClass.list()[0]
assert someFind
assertTrue someFind.createdAt != null
// println "Date: $someFind.createdAt"
// println "Name: $someFind.name"
}
}
I hope it can be helpful.
I have just created class structure as yours (Grails 2.1.0) and there is no problem. It works when mocked and unit-tested. The same when scaffolded and SomeClass and ThirdClass instances saved from forms.
Try clean your DB, especially if you haven't used 'create-drop' mode. Maybe there is some old constraint left.
Last thing, you haven't specified when the error occurs - on save (create or update)? It's rather not probable to get JDBC exception on property set, is it?
I don't remember for sure but it's possible that simple property isn't cascaded by default then try to save SomeClass instance before saving the ThirdClass instance. Also you can auto-cascade instead of declaring simple property by use hasOne relation like:
class ThirdClass {
...
static hasOne = [baseProperty:BaseClass]
}
I defined an annotation as follows
import java.lang.annotation.ElementType
import java.lang.annotation.Inherited
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
/**
* Annotation for any object that exposed a remote interface
*/
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Remote {
String label()
}
and i'm trying to use it this way
import com.yascie.annotation.Remote
#Remote("Bar")
class Foo {
String name
String value
static String code
}
I keep getting though an error saying that the annotation is missing element label
java.lang.annotation.IncompleteAnnotationException: Remote missing element label
Now when i tried to inspect the annotation object i can see that a label method is available trough a proxy but i can't access it. Any ideas ?
Remote annotation = objectClass.clazz.getAnnotation(Remote.class);
annotation.metaClass.methods.each {println it}
public final java.lang.String $Proxy14.label()
ken
You have two options. If you want to use the #Remote("Bar") syntax then you need to change the label() method to value() since that's the method name for the default property for annotations when the name isn't specified.
If you want it to be called label() though, specify it as #Remote(label="Bar")