I am in the middle of trying to refactor some of my data models, but I've run into a problem that I don't understand.
Originally I had a simple data model comprised of 3 entity classes, which looked something like this:
#Entity
public final class Teacher {
#Id
private Long id;
private String primarySubject;
public Teacher() {}
public Teacher(String primarySubject) {
this.primarySubject = primarySubject;
}
//getters & setters
}
#Entity
public final class Student {
#Id
private String username;
#Load
#Index
private Ref<Teacher> homeRoomTeacher;
public Student() {}
public Student(String username, Teacher teacher) {
this.username = username;
homeRoomTeacher = Ref.create(teacher);
}
//getters & setters
}
#Entity
public final class School {
#Id
private String name;
#Load
private Set<Ref<Teacher>> teachers;
#Load
private Set<Ref<Student>> students;
public School() {}
public School(String name) {
this.name = name;
}
//getters & setters
}
And this all worked fine.
But we decided that it would be more useful for us to embed the entities directly instead of Refs...
#Entity
#Embed
public final class Teacher {
#Id
private Long id;
private String primarySubject;
public Teacher() {}
public Teacher(String primarySubject) {
this.primarySubject = primarySubject;
}
//getters & setters
}
#Entity
#Embed
public final class Student {
#Id
private String username;
#Index
private Ref<Teacher> homeRoomTeacher;
public Student() {}
public Student(String username, Teacher teacher) {
this.username = username;
homeRoomTeacher = Ref.create(teacher);
}
//getters & setters
}
#Entity
public final class School {
#Id
private String name;
private Set<Teacher> teachers;
private Set<Student> students;
public School() {}
public School(String name) {
this.name = name;
}
//getters & setters
}
After making those changes, then all of our junit tests started to fail with an AssertionError during registration of the School class in our test setup methods which look like:
#Before
public void setUp() throws Exception {
helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
helper.setUp();
ObjectifyService.register(Teacher.class);
ObjectifyService.register(Student.class);
ObjectifyService.register(School.class);
// more setup
}
The AssertionError doesn't appear until the line that registers the School class, and according to the stack trace is being thrown from the method "com.googlecode.objectify.impl.translate.CreateContext.enterCollection" but I'm not certain how to go about fixing it.
Does anyone have any ideas?
I suspect the error you are getting is to do with the fact that you are trying to register a class which you have annotated with #Embed.
The objectify documentation clearly states that #Embed classes do not have to be registered - maybe this is the cause of the issue.
Also, I'm not 100% sure on this but I don't think you need #Id on an embedded class.
I would suggest you give the following changes a go:
#Embed
public final class Teacher {
#Id
private Long id;
private String primarySubject;
public Teacher() {}
public Teacher(String primarySubject) {
this.primarySubject = primarySubject;
}
//getters & setters
}
#Embed
public final class Student {
#Id
private String username;
#Index
private Ref<Teacher> homeRoomTeacher;
public Student() {}
public Student(String username, Teacher teacher) {
this.username = username;
homeRoomTeacher = Ref.create(teacher);
}
//getters & setters
}
#Before
public void setUp() throws Exception
{
helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
helper.setUp();
ObjectifyService.register(School.class);
// more setup
}
Hope this helps!
Related
I'm using hibernate with manyToMany relation and I want to display data from database
Thank you in advance.
I get this errors:
database :
Here is the code :
Class EnseignerId :
#Embeddable
public class EnseignerId implements Serializable {
//id professeur
#Column(name="professeur_code")
private int code;
//id matiere
#Column(name="matiere_reference")
private String reference;
public EnseignerId() {
super();
}
//getters and setters...
Class Enseigner :
#Entity
#Table(name="Enseigner")
public class Enseigner {
#EmbeddedId
private EnseignerId id = new EnseignerId();
//id prof
#ManyToOne
#MapsId("code")
private Professeur professeur;
//id matiere
#ManyToOne
#MapsId("reference")
private Matiere matiere;
#Column(name="heures")
private int heures;
//constructor getters and setters...
Class Professeur:
#Entity
#Table(name="professeur")
public class Professeur {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="code")
private int code ;
#Column(name="nom")
private String nom;
#Column(name="prenom")
private String prenom;
...
#OneToMany(
mappedBy="professeur",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Enseigner> matieres; //List<Association> Class; //I followed a tutorial
//constructor getters and setters...
public List<Enseigner> getMatieres() {
return matieres;
}
Class Matiere :
#Entity
#Table(name="matiere")
public class Matiere {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="reference")
private String reference;
#Column(name="description")
String description;
#Column(name="volume")
int volume;
#OneToMany(
mappedBy= "matiere",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Enseigner> professeurs;
//constructor getters and setters...
getProfesseur() method :
public Professeur getProfesseur(int code) {
SessionFactory sessionFactory = getSessionFactory(); //static method
Session session = sessionFactory.openSession();
Professeur professeur = null;
try {
session.getTransaction().begin();
System.out.println("------------Calling getProfesseur()----------");
professeur = session.get(Professeur.class, code);
if(professeur != null) {
System.out.println(professeur);
}else {
throw new DAOException( "CODE INVALIDE!" );
}
}
catch(Exception e ) {
System.out.println(e.getMessage());
}
finally {
session.close();
}
return professeur;
}
Saving data and getting professors who don't have an Matiere work. but getting Matiere or professeur whose primary key exists in the join table Enseigner generate errors when I do something like :
Professeur prof =profDAO.getProfesseur(2); //*generates errors* //the professor with id=2 exists in database
System.out.println(prof);
List<Enseigner> enseigner = prof.getMatieres(); //*generates errors*...
List<Matiere> matieres = new ArrayList<>();
for(Enseigner ens : enseigner) {
matieres.add(ens.getMatiere());
System.out.println(ens);
}
/*for(Matiere mat : matieres) {
System.out.println(mat);
}*/
This problem has nothing to do with Hibernate. Please inspect the stack trace carefully: your Enseigner.toString() calls Professeur.toString() which in turn calls Enseigner.toString() again and so on.
I notice this problem more and more these days when people blindly use Lombok with its #Data (which should almost never be used), #ToString and #EqualsAndHashCode. These generate respective methods that include all fields!
You need to remove these annotations or set them up so that they use only the fields that you really need. Most of the time your equals() and hashCode() are not needed when you write web apps with ORM. Hibernate ensures you don't have 2 instances of the same entity.
On the other hand toString() can be useful, but we shouldn't include all fields in it - just the ones that are helpful in identifying the entity.
You have cyclic reference. You need exclude field professeurs and matieres by #JsonIgnoreProperties
I am using spring boot along with react js and postgresql. I am trying to print the rows of table from postgresql to a react js page. I have used crud repository function findAll() in the controller method to get the List. My problem is that when I am printing the List in spring boot console, it prints the list but it's printing empty objects' list when that url is accessed.
User.java
#Entity
#Table(name="users")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name="name")
private String name;
#Column(name="email")
private String email;
public User() {
}
public User(String name, String email) {
this.name = name;
this.email = email;
}
#Override
public String toString() {
return String.format("User[id=%d, name='%s', email='%s']",this.id,this.name,this.email);
}
}
UserRepository.java
public interface UserRepository extends CrudRepository<User, Long>{
}
WebController.java
public class WebController {
#Autowired
private UserRepository repository;
#GetMapping("home")
public String home() {
System.out.println("whaaat");
return "hi ssup";
}
#GetMapping("/save")
public String process() {
repository.save(new User("vidhi","vd#gmail.com"));
System.out.print("apple ");
return "Done";
}
#GetMapping("findall")
#ResponseBody
public Collection<User> findAll() {
System.out.println("cc");
List<User> users = (List<User>) repository.findAll();
System.out.println(users);
return users;
}
}
On printing users in boot: [User[id=33, name='i', email='vd#gmail.com'], User[id=34, name='v', email='d#gmail.com']
on localhost:8080/findall: [{},{}]
What's going on wrong here? I am very confused and trying to figure this out since a lot of time and it's eating my head.
Any help would be wonderful!
Thanks for your time.
You have to add getters and setters to the User class.
Change it to:
#GetMapping("findall", produces= MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<Collection<User>> findAll() {
System.out.println("cc");
List<User> users = (List<User>) repository.findAll();
System.out.println(users);
return ResponseEntity.ok(users);
}
change your repo to:
#Repository
public interface UserRepository extends JpaRepository<User, Long>{
}
Im trying to save info to DynamoDB but im currently getting the error java.lang.NullPointerException: null when using "save" on the AccountHelper class.
I followed the starter guide found on Github; https://github.com/derjust/spring-data-dynamodb
Here is my Model Class;
#DynamoDBTable(tableName = "Users")
public class User {
// #Id
private String _id;
private String bloodGroup;
private String firstName; // DO NOT change this, needs to stay firstName
private String surname;
private String email;
private String password;
private String addressline;
private String postcode;
private String latitude;
private String longitude;
public User() {}
// More Constructors, Getters & Setters
DynamoDB Config Class;
#EnableDynamoDBRepositories(includeFilters = {#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {DynamoDBRepo.class})})
#Configuration
public class DynamoDBConfig {
#Value("${amazon.aws.accesskey}")
private String amazonAWSAccessKey;
#Value("${amazon.aws.secretkey}")
private String amazonAWSSecretKey;
public AWSCredentialsProvider amazonAWSCredentialsProvider() {
return new AWSStaticCredentialsProvider(amazonAWSCredentials());
}
#Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(amazonAWSAccessKey, amazonAWSSecretKey);
}
#Primary
#Bean
public DynamoDBMapperConfig dynamoDBMapperConfig() {
return DynamoDBMapperConfig.DEFAULT;
}
#Bean
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig config) {
return new DynamoDBMapper(amazonDynamoDB, config);
}
#Bean
public AmazonDynamoDB amazonDynamoDB() {
return AmazonDynamoDBClientBuilder.standard().withCredentials(amazonAWSCredentialsProvider())
.withRegion(Regions.US_EAST_1).build();
}
}
Here is the method/class where i am getting the error;
#Service
public class AccountHelper {
private DynamoDBRepo dynamoDBRepo;
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public User create(String bloodGroup, String firstname, String surname, String email, String password, String addressline, String postcode) {
// Getting the error here
return dynamoDBRepo.save(new User(bloodGroup, firstname, surname, email, bCryptPasswordEncoder.encode(password), addressline, postcode));
}
// More methods below that i am not adding to keep this question to a minimum.
Here is my controller;
#Controller
#Component
public class AccountController {
#Autowired
private AccountHelper Service_functions;
#ResponseBody // Works
#PostMapping(value = "/create/{bloodGroup}/{firstname}/{surname}/{email}/{password}/{addressline}/{postcode}")
public String create( #PathVariable String bloodGroup , #PathVariable String firstname, #PathVariable String surname, #PathVariable String email, #PathVariable String password, #PathVariable String addressline, #PathVariable String postcode){
User CreateUser = Service_functions.create(bloodGroup, firstname, surname, email, password, addressline, postcode);
System.out.println("this is working");
return CreateUser.toString();
}
account properties;
spring.application.name=account-service
server.port=8020
eureka.client.service-url.defaultZone=http://localhost:8001/eureka/
amazon.aws.accesskey="" // i removed the keys
amazon.aws.secretkey=""
Any Suggestions/Help would be greatly on where i am going wrong.
Two things you need to fix here based on your details provided.
Add #Autowired annotation on your dynamoDBRepo variable so that it can be recognised as spring managed bean.
Based on your comment
i.e. error saying that it cannot find
com.bdonor.accountservice.Repository.DynamoDBRepo
You need to include com.bdonor.accountservice.Repository package as JPA repository package and enable jpa repository scan in your configuration.
I have 2 Entities: Employee and Specialty.
Every Employee can have some Specialties.
POJOs are generated.
#Entity(indices = {#Index(value = {"f_name", "l_name", "birthday",
"avatarLink"}, unique = false)}, inheritSuperIndices = true)
public class Employee implements Serializable {
#PrimaryKey(autoGenerate = true)
private int employeeId;
private String f_name;
private String l_name;
private String birthday;
#Ignore
private int age;
private String avatarLink;
#Embedded
private List<Specialty> specialty;
private final static long serialVersionUID = -8824149947485321362L;
#Ignore
public Employee() {
}
public Employee(int employeeId, String f_name, String l_name, String
birthday, String avatarLink, List<Specialty> specialty) {
this.employeeId = employeeId;
this.f_name = f_name;
this.l_name = l_name;
this.birthday = birthday;
this.avatarLink = avatarLink;
this.specialty = specialty;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
And some more setters\getters...
And Specialty
#Entity
public class Specialty implements Serializable {
#PrimaryKey
private int specId;
private String specName;
private final static long serialVersionUID = 4288061416169200241L;
public Specialty(int specId, String specName) {
this.specId = specId;
this.specName = specName;
}
#Ignore
public Specialty() {
}
public int getSpecId() {
return specId;
}
And some more setters\getters...
I have this error:
error: Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
I check so many questions and read docs, but it not helps me. Thank you
you should add #Ignore to serialVersionUID fields.
In view of Room, it's just another column.
#Ignore
private final static long serialVersionUID = 4288061416169200241L;
I am trying to get the user's friends list from Facebook.
The problem seems to be the Javabean...
FBUser fbuser = new Gson().fromJson(jsonStr, FBUser.class);
public class FBUser implements Serializable {
private static final long serialVersionUID = -3154429420153433117L;
private String id;
private String name;
private String email;
private Friends friendsList = new Friends();
private FBUser() { }
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<Data> getFriendsList() {
return friendsList.getData();
}
public static class Friends implements Serializable {
private static final long serialVersionUID = 6991758772193514527L;
private List<Data> data;
private Friends() { }
public List<Data> getData() {
return data;
}
public void setData(List<Data> data) {
this.data = data;
}
public class Paging implements Serializable {
private static final long serialVersionUID = 1689816298710621080L;
private String next;
private Paging() { }
public String getNext() {
return next;
}
public void setNext(String next) {
this.next = next;
}
}
}
public class Data implements Serializable {
private static final long serialVersionUID = -5008541658519841090L;
private String id;
private String name;
private Data() { }
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
Json:
json: {"id":"10861234","name":"Whatever","email":"whatever\u0040gmail.com","friends":{"data":[{"name":"Someone","id":"10861234"},{"name" ...43"}],"paging":{"next":"https:\/\/graph.facebook.com\/10861234\/friends..."}}}
The fields ID, Name and Email I can retrieve succesfully... but the friendsList is null... =(
Maybe it is the way I am trying to get it from the nested class, any suggestions on that?
There is no friendsList in your JSON (or, there's no friends in your Java class - whichever way you'd like to look at it). Gson silently ignores anything in the JSON that is not present in your classes.
You have a field friends whose value is an object. That object has a field data which is an array of objects and a field paging which is another object.
You need to write Java classes that match that structure. You're ... close.
In your FBUser class change:
private Friends friendsList = new Friends();
to:
private Friends friends = new Friends();
or:
#SerializedName("friends")
private Friends friendsList = new Friends();
Then in your Friends class you need to add:
private Paging paging = new Paging();
Also note that you don't have to initialize these values unless you specifically don't want them to be non-null when using these classes elsewhere.