Does Objectify permit all types of visibility for Entity fields? - visibility

The sample Objectify code shows entity fields declared with default visibility, e.g.,
public class Car
{
#Id Long id;
String vin;
int color;
#Transient String doNotPersist;
}
Does it matter if I declare the fields private, protected, or public instead?

Based on this example, which I found a few hours after posting my question, persisted fields can be private.

Related

Cyclic dependency with JPA/Hibernate and Jackson [duplicate]

This question already has answers here:
Infinite Recursion with Jackson JSON and Hibernate JPA issue
(29 answers)
Closed 3 months ago.
I have a Spring Boot application using JPA/Hibernate in its persistence layer. The application has read-only access to a database and basically has three entities Article, Category, and Field, which have the following relationships.
Article (*) -> (1) Category (*) <-> (1) Field
That is, an Article has a Category, and a Category always belongs to a single Field, however, multiple Category instances can belong to the same Field.
The application provides two REST endpoints, which give a single Article and a single Field by their IDs, respectively. Of course, this cannot work when using Jackson for serialization due to the cyclic dependency Category <-> Field.
What I want is when I retrieve an Article, it should give me its Category including the category's Field, but not all the other Category instances that belong to the this same Field. On the other hand, when I retrieve a Field, it should give me the Field including all Category instances that belong to this Field.
How can I achieve this?
Edit:
I basically have a similar question as Jackson infinite loops many-to-one one-to-many relation
You can use interface-based projections, to only retrieve needed properties, since Spring Data allows modeling dedicated return types, to more selectively retrieve partial views of the managed aggregates.
Let's assume the entities are declared as shown below. For simplicity, only the id attribute is defined alongside association-mapping attributes.
#Entity
public class Article {
#Id
private Long id;
#ManyToOne
private Category category;
}
#Entity
public class Category {
#Id
private Long id;
#OneToMany
private Set<Article> articles;
#ManyToOne
private Field field;
}
#Entity
public class Field {
#Id
private Long id;
#OneToMany
private Set<Category> categories;
}
For the first endpoint where the Article is fetched by id, the projections should be declared as follows:
public interface ArticleDto {
Long getId();
CategoryDto1 getCategory();
interface CategoryDto1 {
Long getId();
FieldDto1 getField();
}
interface FieldDto1 {
Long getId();
}
}
The important bit here is that the properties defined here exactly
match properties in the aggregate root.
Then, the additional query method should be defined in ArticleRepository:
interface ArticleRepository extends JpaRepository<Article, Long> {
Optional<ArticleDto> findDtoById(Long id);
}
The query execution engine creates proxy instances of that interface
at runtime for each element returned and forwards calls to the exposed
methods to the target object.
Declare additional projections to retrieve properties needed for the second case:
public interface FieldDto2 {
Long getId();
Set<CategoryDto2> getCategories();
interface CategoryDto2 {
Long getId();
}
}
Lastly, define the following query method in FieldRepository:
interface FieldRepository extends JpaRepository<Field, Long> {
Optional<FieldDto2> findDtoById(Long id);
}
With this approach, the infinite recursion exception would never appear, as long as projections don't contain attributes causing recursion.

Can sql query result be manually mapped with room?

Lets say in my dao class i have a method annotated with sql: SELECT id, name, lat, long FROM table WHERE id = :id.
i want to map that to object like (pseudo):
public class Something {
public string Id;
public string Name;
public GeoLocation Location;
public Something(id, name, lat, long) {
this.Id = id;
this.Name = name;
this.Location = new GeoLocation(lat, long);
}
}
so, point is that i want to map flat select result into model with children made from some of the return fields.
Important is that i don’t want to have public get/set for all fields that sql returns.
I also want to avoid any room annotations on Something if possible (i am aware of solutions that involve #Embedded annotations).
In room the only possible way to convert fields into POJO that has no boiler point is indeed #Embedded annotation. Thats the best and simplest way to do it.
You can convert your sql query to your desired model with some other few methods which are not feasible.
Intermediate Model. That is convert your SQL result to a model that one to one matches to your fields. i.e.
public class PreSomething {
public string id;
public string name;
public long lat;
public long long;
}
After converting to PreSomething, you can have it get converted Something with any fashion you like.
Another way would be TypeConverters which changes database schema and will require you have database migration.
So, the only possible way is infact #Embedded. Now coming to your requirements,
Important is that i don’t want to have public get/set for all fields
that sql returns.
Every field that's stored in the database needs to be either public or have a "getter" method. Since your fields are all public you don't have to have any get/set for the fields.
I also want to avoid any room annotations on Something if possible (i
am aware of solutions that involve #Embedded annotations).
You have to annotate #Embedded the GeoLocation object (not Something) in order to be able to map your fields to a POJO.
One other thing to note that you SQLite, in that fashion Room, is case sensitive so. If you have to specify your fields with lowercase if your columns are lowercase. Otherwise you have to annotate them with #ColumnInfo and correct column name.

Hibernate Search #IndexedEmbedded on a polymorphic relationship (#Any, #ManyToAny)

I'm using Hibernate Search and looking to index an object that has polymorphic relationships that use #Any and/or #ManyToAny.
#Indexed
public class Foo {
#Any(metaDef="fooOwnerType", metaColumn=#Column(name="ownerType"))
#JoinColumn(name="ownerId")
#IndexedEmbedded // this DOES NOT WORK
private OwnerType owner;
#OneToOne
#IndexedEmbedded // this WORKS
private User user;
#OneToOne
#IndexedEmbedded // this WORKS
private Company company;
#Field
private String description;
}
#Indexed
public class User implements OwnerType {
#Field
private String name;
#Field
private String address;
}
public class Company implements OwnerType {
#Field
private String name;
}
public interface OwnerType {
}
I can search and find Foo objects using text in the description field without issue. What I'd also like to do is find Foo objects when User.name or User.address is matched... but Hibernate Search doesn't seem to index these fields for me due to the polymorphic relationship OwnerType owner.
It would work fine if I use #IndexedEmbedded on a concrete object (User or Company) directly as expected.
Yes, this is expected. #IndexedEmbedded only adds fields for the exposed type of the embedded field. There are no concrete plans to fix it at the moment, but there is a feature request here: https://hibernate.atlassian.net/browse/HSEARCH-438
Also, interfaces cannot be mapped for indexing, only classes can. This will be fixed in Search 6: https://hibernate.atlassian.net/browse/HSEARCH-1656
One way to make your code work would be to turn OwnerType into an abstract class, either a #MappedSuperclass or an #Entity, and move the fields that are common to every subclass there.
EDIT: If the user/company associations are mutually exclusive (only one can be non-null), another way to make it work would be to simply query both. For example instead of querying owner.name, query both fields user.name and company.name. The Hibernate Search DSL allows that: just use .onFields("user.name", "company.name") instead of .onField("owner.name").

How do I get Spring's Data Rest Repository to retrieve data by its name instead of its id

I am using Spring Data's Rest Repositories from spring-boot-starter-data-rest, with Couchbase being used as the underlining DBMS.
My Pojo for the object is setup as so.
#Document
public class Item{
#Id #GeneratedValue(strategy = UNIQUE)
private String id;
#NotNull
private String name;
//other items and getters and setters here
}
And say the Item has an id of "xxx-xxx-xxx-xxx" and name of "testItem".
Problem is, that when I want to access the item, I need to be accessible by /items/testItem, but instead it is accessible by /items/xxx-xxx-xxx-xxx.
How do I get use its name instead of its generated id, to get the data.
I found out the answer to my own question.
I just need to override the config for the EntityLookup.
#Component
public class SpringDataRestCustomization extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.withEntityLookup().forRepository(UserRepository.class).
withIdMapping(User::getUsername).
withLookup(UserRepository::findByUsername);
}
}
Found the info here, though the method name changed slightly.
https://github.com/spring-projects/spring-data-examples/tree/master/rest/uri-customization
If you want query the item by name and want it perform as querying by id,you should make sure the name is unique too.You cant identify a explicit object by name if all objects have a same name,right?
With jpa you could do it like:
#NotNull
#Column(name="name",nullable=false,unique=true)
private String name;

Spring Data Couchbase put #Id attribute to json when embedded

I have a one to many relationship namely A and B. A may refer to many B instances. B instances also can be managed independently.
That's why, B class looks like this:
public class B {
#Id
private String id;
private String appId;
}
A class will refer to a list of B instances. So it looks like this:
public class A {
#Id
private String id;
private int age;
private List<B> bInstances;
}
When bInstances are filled with B instances and then A instance is saved, id fields of the B instances are removed from the JSON document since it is annotated with #Id.
I simply need to add this field to JSON when B is embedded into another class.
And when B instance is saved independently, #Id field can be used as the regular key.
How may I do this?
To answer your question specifically, yes the field annotated #Id won't get written to the serialized json. Your best bet here is to duplicate the field and set its value in either the constructor or a setter, for example:
public class B {
#Id
private String metaId;
private String id;
private String appId;
public setMetaId(String metaId) {
this.metaId = metaId;
this.id = metaId;
}
}
You can #JsonIgnore one of them if you don't want to see the duplication in your serializations.
Note: I totally agree with Robin's answer, but there are cases where you want to save the data as-it-was and you want to refer to it in the future.. so you don't care if B instance changed one week after you saved the data. So it really depends on your scenario.
I would strongly advise you to not store the instances of B directly in a document of A. Doing this would result in data inconsistencies if an instance of B is changed in another context than A. Additionally you duplicate data unnecessarily if an instance of B is stored in multiple documents of class A.
The desired way to store instances of one class in another is to save the document ids instead. So your class A should look like this:
public class A {
#Id
private String id;
private int age;
private List<String> bInstanceIds;
}

Resources