#JsonIdentityInfo Causes Undesired Results - spring-mvc

I use hibernate orm to map have a many-to-many relationship between Role and Privilege like so:
Role
#Entity
#Audited
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "roleId")
public class Role extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "role_id")
private Integer roleId;
#Size(max = 45)
#Column(name = "role")
private String role;
#ManyToMany(mappedBy = "roleCollection")
private Collection<Privilege> privilegeCollection;
#ManyToMany(mappedBy = "roleCollection")
#WhereJoinTable(clause = "privilege_privilege_id IN (SELECT ph.parent_privilege FROM privilege_hierachy ph)")
private Collection<Privilege> parentPrivilegeCollection;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "roleId")
#JsonIgnore
private Collection<User> userCollection;
public Role() {
}
//Getters and Setters removed for brevity
}
Privilege
#Entity
#Audited
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "privilegeId")
public class Privilege extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "privilege_id")
private Integer privilegeId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 150)
#Column(name = "description")
private String description;
#Size(max = 45)
#Column(name = "friendly_name")
private String friendlyName;
#JoinTable(name = "role_privilege", joinColumns = {
#JoinColumn(name = "privilege_privilege_id", referencedColumnName = "privilege_id")}, inverseJoinColumns = {
#JoinColumn(name = "role_role_id", referencedColumnName = "role_id")})
#ManyToMany
private Collection<Role> roleCollection;
#JoinTable(name = "privilege_hierachy", joinColumns = {
#JoinColumn(name = "parent_privilege", referencedColumnName = "privilege_id")}, inverseJoinColumns = {
#JoinColumn(name = "child_privilege", referencedColumnName = "privilege_id")})
#ManyToMany
private Collection<Privilege> privilegeCollection;
public Privilege() {
}
// Getter and Setters removed for brevity
}
What i want to get is all Roles with their respective Privileges in JSON. Obviously that brings back StackOverflowError as you can see Role
goes to Privilege which goes back to Role and so on.
Because is many-to-many bidirectional i annotated it with #JsonIdentityInfo both sides of the relation.
The desired result is to get roles with privileges without cyclic stackoverflowerror, but what is get as result is Json below. What i dont understand is items in privilegeCollection some are objects which is fine but why numbers (57,97,165,161,124)... where are those comming from...why not objects

Related

List of unique objects containing unique sub-objects

I am trying to get a list of unique objects where each object further contains a list of unique sub-objects. Uniqueness in below example is determined by the id field in each class.
public class MyMain {
public static void main(String[] args) {
Parent p1 = new Parent(1L);
Child c11 = new Child(11L);
Child c12 = new Child(12L);
Parent p2 = new Parent(2L);
Child c21 = new Child(21L);
Child c22 = new Child(22L);
Child c23 = new Child(23L);
Holder holder1 = new Holder(p1.getId(), c11.getId());
Holder holder2 = new Holder(p1.getId(), c11.getId());
Holder holder3 = new Holder(p1.getId(), c11.getId());
Holder holder4 = new Holder(p1.getId(), c11.getId());
Holder holder5 = new Holder(p1.getId(), c12.getId());
Holder holder6 = new Holder(p1.getId(), c12.getId());
Holder holder7 = new Holder(p1.getId(), c12.getId());
Holder holder8 = new Holder(p2.getId(), c21.getId());
Holder holder9 = new Holder(p2.getId(), c21.getId());
Holder holder10 = new Holder(p2.getId(), c21.getId());
Holder holder11 = new Holder(p2.getId(), c22.getId());
Holder holder12 = new Holder(p2.getId(), c23.getId());
Holder holder13 = new Holder(p2.getId(), c23.getId());
List<Holder> holders = new ArrayList<>();
holders.add(holder1); holders.add(holder2); holders.add(holder3); holders.add(holder4);
holders.add(holder5); holders.add(holder6); holders.add(holder7); holders.add(holder8);
holders.add(holder9); holders.add(holder10); holders.add(holder11); holders.add(holder12); holders.add(holder13);
}
}
#Value
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
class Parent {
#EqualsAndHashCode.Include
public Long id;
public List<Child> chidren;
public Parent(Long id) { this.id = id; }
}
#Value
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
class Child {
#EqualsAndHashCode.Include
public Long id;
public Child(Long id) { this.id = id; }
}
#Value
class Holder {
Long parentId;
Long childId;
public Holder(Long parentId, Long childId) {
this.parentId = parentId;
this.childId = childId;
}
}
From the code fragment above, I am looking to get a List<Parent> (from holders ) that will contain two parents: p1 and p2. Each parent will then have a List<Child> containing unique children for that parent.
Expected output:
List<Parent> will have p1 and p2
p1.List<Child> will have c11 and c12 (only 2 entries)
p2.List<Child> will have c21, c22, c23 (only 3 entries)
I have worked out how to get a list of unique parents but not sure how to achieve unique children as well.
UPDATE:
Below seems to be working for me, however, not sure if there's a better way.
public class MyMain {
public static void main(String[] args) {
MyMain m = new MyMain();
Parent p1 = new Parent(1L, null);
Child c11 = new Child(11L);
Child c12 = new Child(12L);
Parent p2 = new Parent(2L, null);
Child c21 = new Child(21L);
Child c22 = new Child(22L);
Child c23 = new Child(23L);
Holder holder1 = new Holder(p1.getId(), c11.getId());
Holder holder2 = new Holder(p1.getId(), c11.getId());
Holder holder3 = new Holder(p1.getId(), c11.getId());
Holder holder4 = new Holder(p1.getId(), c11.getId());
Holder holder5 = new Holder(p1.getId(), c12.getId());
Holder holder6 = new Holder(p1.getId(), c12.getId());
Holder holder7 = new Holder(p1.getId(), c12.getId());
Holder holder8 = new Holder(p2.getId(), c21.getId());
Holder holder9 = new Holder(p2.getId(), c21.getId());
Holder holder10 = new Holder(p2.getId(), c21.getId());
Holder holder11 = new Holder(p2.getId(), c22.getId());
Holder holder12 = new Holder(p2.getId(), c23.getId());
Holder holder13 = new Holder(p2.getId(), c23.getId());
List<Holder> holders = new ArrayList<>();
holders.add(holder1); holders.add(holder2); holders.add(holder3); holders.add(holder4);
holders.add(holder5); holders.add(holder6); holders.add(holder7); holders.add(holder8);
holders.add(holder9); holders.add(holder10); holders.add(holder11); holders.add(holder12); holders.add(holder13);
Map<Long, Set<Long>> returnSet= holders.stream()
.collect(Collectors.toMap(Holder::getParentId, x -> m.uniqChildIdSet(x), MyMain::merge));
System.out.println(returnSet);
}
public static Set<Long> uniqChildIdSet(Holder holder) {
HashSet<Long> uniqChild = new HashSet();
uniqChild.add(holder.getChildId());
return uniqChild;
}
public static Set<Long> merge(Set<Long> l1, Set<Long> l2) {
l1.addAll(l2);
return l1;
}
}
#Value
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
class Parent {
#EqualsAndHashCode.Include
public Long id;
public List<Child> chidren;
public Parent(Long id, List<Child> chidren) { this.id = id;
this.chidren = chidren;
}
}
#Value
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
class Child {
#EqualsAndHashCode.Include
public Long id;
public Child(Long id) { this.id = id; }
}
#Value
class Holder {
Long parentId;
Long childId;
public Holder(Long parentId, Long childId) {
this.parentId = parentId;
this.childId = childId;
}
}
Here is what you could use, without any helper methods.
What it's basically doing is the following
Group by the Holder's parent id
For this Holder, take all the childId properties and put them in a Set<Long>
Map<Long, Set<Long>> returnSet = holders.stream()
.collect(Collectors.groupingBy(
Holder::getParentId,
Collectors.mapping(
Holder::getChildId,
Collectors.toSet()
)
)
);
Output
{1=[11, 12], 2=[21, 22, 23]}

oneToMany JPA spring

I am trying to link two errors, but I am falling out
Here's a error:
mappedBy reference an unknown target entity property: com.proxy.ProxyBase.proxy_server in com.accounts.AllAccountsBase.proxies
First model
#Data
#Entity
#Table(name = "all_accounts")
public class AllAccountsBase {
#Id
#Column(name = "login", nullable = false, unique = true)
private String login;
#Column(name = "password")
private String password;
#Column(name = "old_password")
private String oldPassword;
#Column(name = "phone")
private String phone;
#Column(name = "recovery_email")
private String recoveryEmail;
#Column(name = "recovery_pass")
private String recoveryPass;
#Column(name = "virt_machine")
private String machineName;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "personal_data_id")
private PersonalData personalData;
#Column(name = "account_status")
private Integer accountStatus;
#Column(name = "time_update")
private Timestamp timeUpdate;
#Column(name = "server_group")
private String serverGroup;
#Column(name = "server", nullable = false, unique = true)
private String server;
#OneToMany(
mappedBy = "proxy",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
private Collection<ProxyBase> proxies = new ArrayList<>();
}
In the model, I added a relationship one to many, and vice versa in the other
Second model
#Data
#Entity
#Table(name = "proxy")
public class ProxyBase implements Serializable {
#Id
#Column(name = "server", nullable = false, unique = true)
private String server;
#Column(name = "proxy_data")
private String proxyData;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "all_accounts_server")
private AllAccountsBase allAccountsBase;
}
Help please
I did it differently:
#Data
#Entity
#Table(name = "proxy")
public class ProxyBase implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "server", nullable = false)
private String server;
#Column(name = "proxy_data")
private String proxyData;
}
and
#Data
#Entity
#Table(name = "all_accounts")
public class AllAccountsBase implements Serializable {
#Id
#Column(name = "login", nullable = false, unique = true)
private String login;
#Column(name = "password")
private String password;
#Column(name = "old_password")
private String oldPassword;
#Column(name = "phone")
private String phone;
#Column(name = "recovery_email")
private String recoveryEmail;
#Column(name = "recovery_pass")
private String recoveryPass;
#Column(name = "virt_machine")
private String machineName;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "personal_data_id")
private PersonalData personalData;
#Column(name = "account_status")
private Integer accountStatus;
#Column(name = "time_update")
private Timestamp timeUpdate;
#Column(name = "server_group", nullable = false)
private String serverGroup;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "proxy_key",
joinColumns = #JoinColumn(name = "server_group", referencedColumnName = "server_group"),
inverseJoinColumns = #JoinColumn(name = "proxy_server_group", referencedColumnName = "server"))
private Collection<ProxyBase> proxies = new ArrayList<>();
}

How to prevent duplicate validation while updating the value without any changes?

#RequestMapping(value = "/updateYearMaster", method = RequestMethod.POST)
public String updateYearmaster(#RequestParam(value = "id", required = false) Long id,
#RequestParam(value = "fromyear", required = false) Date fromyear,
#RequestParam(value = "toyear", required = false) Date toyear,
#RequestParam(value = "status", required = false) String status,
#RequestParam(value = "yeardescription", required = false) String yeardescription, Model model) {
Yearmaster yearmaster = new Yearmaster(fromyear, toyear, status, yeardescription);
yearmaster.setId(id);
List val = yearmasterService.duplicateEditYear(fromyear, toyear, id);
if (!val.isEmpty()) {
model.addAttribute("yearmaster", yearmaster);
errorMessage = "fromyear and toyear combination is already exist";
model.addAttribute("errorMessage", errorMessage);
return "edit-year-master";
} else {
yearmasterService.save(yearmaster);
return "redirect:/yearmaster";
}
}

Save user profile information _userManager.UpdateAsync(user);

I'm trying to get Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta6 to write some information to the current ApplicationUser "profile" but the value is null and I don't get any exceptions running the following code.
public class TestController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public TestController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
// GET: /<controller>/
public async Task<ActionResult> Index()
{
var userObject = await _userManager.FindByIdAsync(Context.User.GetUserId());
//This value is null even the second time I hit this breakpoint.
var shouldHaveAValue = userObject.MyStringList;
userObject.MyStringList = new List<string>();
userObject.MyStringList.Add("testId");
await _userManager.UpdateAsync(userObject);
return View();
}
}
I might be completely wrong here but this is the way I figured it should be done when I saw
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
public virtual List<string> MyStringList { get; set; }
}
The example is implemented in the ASP.NET5 web template.
//Edit:
Could it be the way I added the column? I did this since I get errors running the migrations commands which is stated not to be ready on the ef documentation page.( dnx . ef apply )
migration.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column(type: "nvarchar(450)", nullable: false),
AccessFailedCount = table.Column(type: "int", nullable: false),
ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true),
Email = table.Column(type: "nvarchar(max)", nullable: true),
EmailConfirmed = table.Column(type: "bit", nullable: false),
LockoutEnabled = table.Column(type: "bit", nullable: false),
LockoutEnd = table.Column(type: "datetimeoffset", nullable: true),
NormalizedEmail = table.Column(type: "nvarchar(max)", nullable: true),
NormalizedUserName = table.Column(type: "nvarchar(max)", nullable: true),
PasswordHash = table.Column(type: "nvarchar(max)", nullable: true),
PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true),
PhoneNumberConfirmed = table.Column(type: "bit", nullable: false),
SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true),
TwoFactorEnabled = table.Column(type: "bit", nullable: false),
UserName = table.Column(type: "nvarchar(max)", nullable: true),
MyStringList = table.Column(type: "nvarchar(max)", nullable: true)
},

What's wrong with this linqTOsql self referencing object mapping?

I'm trying to create a self referencing object using linqTOsql mapping. So far, I am definitely in over my head. Here's the code I have:
[Table]
public class Category
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public Int64 catID { get; set; }
public Int64 parentCatID { get; set; }
public string catName { get; set; }
public string catDescription { get; set; }
internal EntityRef<IEnumerable<Category>> _category;
[Association(ThisKey = "parentCatID", Storage = "_category")]
public IEnumerable<Category> category {
get { return _category.Entity; }
set { _category.Entity = value; }
}
}
My fakeRepository is defined like this:
// Fake hardcoded list of categories
private static IQueryable<Category> fakeCategories = new List<Category> {
new Category { catID = 1, parentCatID = 0, catName = "Root", catDescription = "" },
new Category { catID = 2, parentCatID = 1, catName = "Category w/subs", catDescription = "" },
new Category { catID = 3, parentCatID = 1, catName = "Category no subs but now has subs", catDescription = "" },
new Category { catID = 4, parentCatID = 2, catName = "Zub Cat", catDescription = "" },
new Category { catID = 5, parentCatID = 2, catName = "Sub Cat", catDescription = "" },
new Category { catID = 6, parentCatID = 0, catName = "Another Root", catDescription = "" },
new Category { catID = 7, parentCatID = 0, catName = "Ze German Root", catDescription = "" },
new Category { catID = 8, parentCatID = 3, catName = "Brand new cats", catDescription = "" },
new Category { catID = 9, parentCatID = 8, catName = "Brand new cats sub", catDescription = "" },
}.AsQueryable();
I pass Category to the view like this:
public ActionResult CategoryTree()
{
IQueryable<Category> cats = genesisRepository.Category
.Where(x => x.parentCatID == 0)
.OrderBy(x => x.catName);
return View(cats);
}
The problem that I'm running into is that all of this compiles, but I don't get anything beyond the root categories. Model[0].category is returning null.
What is wrong with my self-referencing object?
Edit
I wonder if it's not working because I don't have a real linq-to-sql data context in my fakeRepository. If that's the case, is there a way around that? Can I can get this to work without a connection to a database?
Yeah, you hit the nail on the head. It's not working because you're using a fake repository.
Linq-to-Sql does all the wiring up for you and sets the related collections based on the properties (& their attributes) that you setup in your model.
I don't know how to accomplish this without a connection to the database because internal EntityRef<IEnumerable<Category>> _category; is completely foreign to me - I'm more of a POCO model type of guy.
After a quick google, I found this - How to: Map Database Relationships (LINQ to SQL)
Could you change your model to read:
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public Int64 CatId { get; set; }
[Column]
public Int64 ParentCatId { get; set; }
[Column]
public string CatName { get; set; }
[Column]
public string CatDescription { get; set; }
private EntitySet<Category> _ChildCategories;
[Association(Storage = "_ChildCategories", OtherKey = "ParentCatId")]
public EntitySet<Category> ChildCategories
{
get { return this._ChildCategories; }
set { this._ChildCategories.Assign(value); }
}
private EntityRef<Category> _ParentCategory;
[Association(Storage = "_ParentCategory", ThisKey = "ParentCatId")]
public Category ParentCategory
{
get { return this._ParentCategory.Entity; }
set { this._ParentCategory.Entity = value; }
}
Now because your ChildCategories is of type EntitySet<Category> (which inherits from IList<T>) you should be able to wire fake relationships up yourself.
So you could do something like this:
private static IQueryable<Category> GetFakeCategories()
{
var categories = new List<Category> {
new Category { CatId = 1, ParentCatId = 0, CatName = "Root", CatDescription = "" },
new Category { CatId = 2, ParentCatId = 1, CatName = "Category w/subs", CatDescription = "" },
//Blah
new Category { CatId = 8, ParentCatId = 3, CatName = "Brand new cats", CatDescription = "" },
new Category { CatId = 9, ParentCatId = 8, CatName = "Brand new cats sub", CatDescription = "" }
};
//Loop over the categories to fake the relationships
foreach (var category in categories)
{
category.ChildCategories = new EntitySet<Category>(); //new up the collection
foreach (var subLoopCategory in categories)
{
if (category.ParentCatId == subLoopCategory.CatId)
category.ParentCategory = subLoopCategory;
if (category.Id == subLoopCategory.ParentCatId)
category.ChildCategories.Add(subLoopCategory);
}
}
return categoies.AsQueryable();
}
It works in my head at least... :-)
HTHs,
Charles
EDIT: Re: Comment below about a null reference on _childCategories.
You could change the model to look like:
private EntitySet<Category> _ChildCategories = new EntitySet<Category>();
It is supposed to be null. You are getting all categories where the ParentId = 0 ... and you don't have a child with an Id of 0. So that seems right to me.
It is not showing any subcategories because it has no subcategories to show. Try this:
IQueryable<Category> cats = genesisRepository.Category
.Where(x => x.parentCatID != 0)
.OrderBy(x => x.catName);
The parentCatId needs to point to a valid CatId for it to be a subcategory. This query should get you all the categories that are subcategories.

Resources