Unexpected route name in spring - java

I have 3 controllers on my spring app. Each one of them have different name then I set up for example I have
#RestController
#RequestMapping("/operator")
public class OperativesController {
and when run it on localhost and check available routes this is my output
{
"_links" : {
"operativeses" : {
"href" : "http://localhost:8080/operativeses"
}
}
}
I would appreciate if someone would tell me that where this name is coming from?
PS. yesterday everything was all right.
Not sure if that is helpful for you but below you can find my properties
logging.level.org.hibernate=INFO
spring.jpa.show-sql=true
hibernate.dialect = org.hibernate.dialect.SQLServer2016Dialect
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.ddl-auto=none
EDIT
I just debug this spring app and find out that, my path are created from "Entities". So I have entity names Operatives and spring picking up it as URL, so it automatically creating path like operativeses (why? I do not know) because I change name of this entity to 'Operativesasd' and in the result I have path 'Operativesasds' (notice s on the end)
So my question now is, Why my spring app creating path base on entities even if I have controllers?
my entity looks like
#Entity
#Table(name="operatives", schema = "lm")
public class Operatives implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name", length=150)
private String name;
#Column(name = "level", length=7)
private String level;
#Column(name="is_qa", length=50)
private String isQa;
#Column(name="is_active", length=5)
private String isActive;
#Column(name="is_admin", length=50)
private String isAdmin;
public Operatives() {
super();
}
public int getId() {
return id;
}
public void setId(int aId) {
id = aId;
}
public String getName() {
return name;
}
public void setName(String aName) {
name = aName;
}
public String getLevel() {
return level;
}
public void setLevel(String aLevel) {
level = aLevel;
}
public String getIsQa() {
return isQa;
}
public void setIsQa(String aIsQa) {
isQa = aIsQa;
}
public String getIsActive() {
return isActive;
}
public void setIsActive(String aIsActive) {
isActive = aIsActive;
}
public String getIsAdmin() {
return isAdmin;
}
public void setIsAdmin(String aIsAdmin) {
isAdmin = aIsAdmin;
}
}

Related

How to pass #EmbeddedId in POST json in spring-boot data rest

I have built a REST API using Spring Boot Data REST. I'm using an embeddedId and have also implemented a BackendIdConverter.
Below is my Embeddable class
#Embeddable
public class EmployeeIdentity implements Serializable {
#NotNull
#Size(max = 20)
private String employeeId;
#NotNull
#Size(max = 20)
private String companyId;
public EmployeeIdentity() {}
public EmployeeIdentity(String employeeId, String companyId) {
this.employeeId = employeeId;
this.companyId = companyId;
}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
public String getCompanyId() {
return companyId;
}
public void setCompanyId(String companyId) {
this.companyId = companyId;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EmployeeIdentity that = (EmployeeIdentity) o;
if (!employeeId.equals(that.employeeId)) return false;
return companyId.equals(that.companyId);
}
#Override
public int hashCode() {
int result = employeeId.hashCode();
result = 31 * result + companyId.hashCode();
return result;
}
}
Here's my Employee model
#Entity
#Table(name = "employees")
public class Employee {
#EmbeddedId
private EmployeeIdentity id;
#NotNull
#Size(max = 60)
private String name;
#NaturalId
#NotNull
#Email
#Size(max = 60)
private String email;
#Size(max = 15)
#Column(name = "phone_number", unique = true)
private String phoneNumber;
public Employee() {}
public Employee(EmployeeIdentity id, String name, String email, String phoneNumber) {
this.id = id;
this.name = name;
this.email = email;
this.phoneNumber = phoneNumber;
}
public EmployeeIdentity getId() {
return id;
}
public void setId(EmployeeIdentity 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 String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
And to have resource links generated properly using my embedded id instead of a qualified class name
#Component
public class EmployeeIdentityIdConverter implements BackendIdConverter {
#Override
public Serializable fromRequestId(String id, Class<?> aClass) {
String[] parts = id.split("_");
return new EmployeeIdentity(parts[0], parts[1]);
}
#Override
public String toRequestId(Serializable source, Class<?> aClass) {
EmployeeIdentity id = (EmployeeIdentity) source;
return String.format("%s_%s", id.getEmployeeId(), id.getCompanyId());
}
#Override
public boolean supports(Class<?> type) {
return Employee.class.equals(type);
}
}
And here's my repository code
#RepositoryRestResource(collectionResourceRel = "employees", path = "employees")
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, EmployeeIdentity> {
}
This works fine with GET requests but I need to be able to POST. The first thing I noticed that when I do a POST with the json
{
"id": {
"employeeId": "E-267",
"companyId": "D-432"
},
"name": "Spider Man",
"email": "spman#somedomain.com",
"phoneNumber": "+91-476253455"
}
This doesn't work. EmployeeIdentityIdConverter#fromRequestId throws a null pointer exception because the string parameter is null. So I added a null check and return default EmployeeIdentity when id is null. As described by this answer https://stackoverflow.com/a/41061029/4801462
Modified EmployeeIdentityIdConverter#fromRequestId
#Override
public Serializable fromRequestId(String id, Class<?> aClass) {
if (id == null) {
return new EmployeeIdentity();
}
String[] parts = id.split("_");
return new EmployeeIdentity(parts[0], parts[1]);
}
But this raised another problem. My implementations for hashCode and equals now through null pointer exceptions since the default constructor was used and the employeeId and companyId are null.
In an attempt to fix this, I gave default values to employeeId and companyId
**Modified Employee#Employee() constructor*
public Employee() {
this.employeeId = "";
this.companyId = "";
}
NOTE
I am not even sure of what I was doing above. I was just trying to fix the small problems as they occurred.
By the way if you guessed this didn't work then you're right. While I didn't get an error and the request was successful, I didn't get the behavior I expected. A new entry was created with empty employeeId and companyId.
How do make POST to REST API whose model uses #EmbeddedId with spring boot data rest?
Here is an other solution. (Still not perfect though.)
Expose the id for your Employee class:
#Configuration
protected class MyRepositoryRestConfigurer implements RepositoryRestConfigurer {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(ThemeMessage.class);
}
}
Add the following line to your converter (during POST requests the id will be null):
#Override
public Serializable fromRequestId(String id, Class<?> aClass) {
if(id==null) {
return null;
}
String[] parts = id.split("_");
return new EmployeeIdentity(parts[0], parts[1]);
}
The following POST request then will work:
{
"id": {
"employeeId": "E-267",
"companyId": "D-432"
},
"name": "Spider Man",
"email": "spman#somedomain.com",
"phoneNumber": "+91-476253455"
}
However, the id field will be exposed in all of the responses. But maybe it's not a real problem, because when you use a composite id it usually means that the id is not only an abstract identifier, but its parts have meaningful content which should appear in the entity body.
Actually, I'm thinking of adding these lines to my own code too .... :)
I had a similar problem and I couldn't find a solution for creating new entities via the POST /entities endpoint.
However, you can also create a new entity via PUT /entities/{newId} endpoint. And the converter works fine for these endpoints.
I also completely denied the POST endpoint avoiding the 500 responses:
#PostMapping(value = "/themeMessages")
public ResponseEntity<Void> postThemeMessage() {
return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED);
}

One-To-Many - How to Link to Objects correctly?

I'm using JPA and have some difficulties to understand how the One-To-Many Realtionship works.
I have the following two classes:
#Entity
public class myCheck {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
protected int Check_id;
#Column
private String name;
#ManyToOne
private mySystem system;
#Override
public String toString() {
return this.name;
}
public int getId() {
return Check_id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public mySystem getLinkSystem() {
return system;
}
public void linkSystem(mySystem system) {
this.system = system;
}
}
and:
#Entity
public class mySystem {
#Id
#GeneratedValue
#Column(name = "system_id")
protected int system_id;
#Column
public String name;
#ManyToOne(cascade=CascadeType.ALL)
private mySystem parent;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "system", fetch = FetchType.EAGER)
private List<myCheck> checks;
public mySystem() {
//subSystems = new ArrayList<mySystem>();
checks = new ArrayList<myCheck>();
}
public boolean linkCheck(myCheck hc) {
return checks.add(hc);
}
public boolean unlinkCheck(myCheck hc) {
return checks.remove(hc);
}
public List<myCheck> getlinkedChecks() {
return checks;
}
public myCheck getLinkCheck(int hcId) {
for (myCheck hc : checks) {
if (hc.getId() == hcId)
return hc;
}
return null;
}
public int getId() {
return system_id;
}
public void setId(int id) {
this.system_id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return this.getName();
}
}
Now I have an existing System in my database, which is loaded:
// load System
EntityManager entityManager1 = entityManagerFactory.createEntityManager();
List<mySystem> systems = entityManager1.createQuery("from mySystem").getResultList();
entityManager1.close();
I want to add two new checks to Systems. What is working is:
EntityManager entityManager2 = entityManagerFactory.createEntityManager();
entityManager2.getTransaction().begin();
myCheck check = new myCheck();
check.setName("Check 1");
check.linkSystem(systems.get(0));
entityManager2.persist(check);
myCheck check2 = new myCheck();
check2.setName("Check 2");
check2.linkSystem(systems.get(0));
entityManager2.persist(check2);
entityManager2.merge(systems.get(0));
entityManager2.getTransaction().commit();
entityManager2.close();
But I can't do this:
EntityManager entityManager2 = entityManagerFactory.createEntityManager();
entityManager2.getTransaction().begin();
myCheck check = new myCheck();
check.setName("Check 1");
systems.get(0).linkCheck(check);
entityManager2.persist(check);
myCheck check2 = new myCheck();
check2.setName("Check 2");
systems.get(0).linkCheck(check);
entityManager2.persist(check2);
entityManager2.merge(systems.get(0));
entityManager2.getTransaction().commit();
entityManager2.close();
The second solution will save the checks, but I don't link them with the system.
Has someone a explanation for this? I really want to understand this.
You have bidirectional relation which means each side of the relation should have a reference to the other side.
so in your persistence logic you will also need to inject the system in your check
myCheck check = new myCheck();
check.setName("Check 1");
check.linkSystem(systems.get(0);
systems.get(0).linkCheck(check);
entityManager2.persist(check);
But in this case you will have a problem if your (systems.get(0)) is not attached to the persistence context because you will be having reference to deatached object when persisting the check, you can either put Cascade on the system inside check class or instead persist the system, it already cascades the check so the check will be persisted

In Spring mvc How to add add set values to mysql

My goal :
In Spring MVC I have to save mobile phone contact list into database.
example:
phone1 sonia 2554654 work
2554654 home
multiple phone_number with multiple phone_Number type
contacts table
id,
contact_name
phone_number
phone_type
in my java class I have
public class ContactMobile {
private String type;
private String number;
public ContactMobile() {
}
public ContactMobile(String type, String number) {
super();
this.type = type;
this.number = number;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
and here I use SET for phone number and type
#Entity
#Table(name = "_contact")
public class MobileContact {
private String id;
private String fullname;
private Set<ContactMobile> mobileNumbers;
public MobileContact(String fullname, Set<ContactMobile> mobileNumbers) {
super();
this.fullname = fullname;
this.mobileNumbers = mobileNumbers;
}
#Id
#Column(name = "Id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "fullname")
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public Set<ContactMobile> getMobileNumbers() {
return mobileNumbers;
}
public void setMobileNumbers(Set<ContactMobile> mobileNumbers) {
this.mobileNumbers = mobileNumbers;
}
public MobileContact() {
super();
}
}
I am using hibernate to store data..
my question is in my MobileContact class in
public Set<ContactMobile> getMobileNumbers() {
return mobileNumbers;
}
what annotation I have to use here to save multiple phonenumbers?
The MobileContact entity has many ContactMobile, it is a OneToMany relation. In your ContactMobile table, you should has a field for the id of MobileContact, like mobile_contact_id, and set the join column on that field as below in your ContactMobile:
#OneToMany(fetch = FetchType.LEZY)
#JoinColumn(name = "mobile_contact_id")
private Set<ContactMobile> mobileNumbers;
You can get the detail about the relation in this.
You can use the Embeddables (instead of Entities) for very simple value objects like MobileContact (then they do not need an ID, and the are no just simple value objects without own identity)
#Embeddable
public class ContactMobile {...
//implement an equals and hashcode method!
}
public class MobileContact {
...
#ElementCollection
private Set<ContactMobile> mobileNumbers;
...
}
#See Java Persistence/ElementCollection

How map Child Object input json in jackson?

I'm developing an application using java with hibernate 4.2.6 and spring 4.0.1. My application is a REST FULL application. for this I use jackson. My entities are as follow:
Calk.java:
#Entity
public class Calk {
#Id
#GeneratedValue
private Long id;
#OneToMany(mappedBy="calk", fetch=FetchType.LAZY)
List<BaseLayer> baseLayer = new ArrayList<BaseLayer>();
public void addBaseLayer(BaseLayer baseLayer){
this.baseLayer.add(baseLayer);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#JsonIgnore
public List<BaseLayer> getBaseLayer() {
return baseLayer;
}
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
}
BaseLayer.java:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="layer")
#JsonSubTypes(
{
#JsonSubTypes.Type(value=PointLayer.class, name="point")
})
#DiscriminatorValue("BaseLayerDiscriminator")
public class BaseLayer {
#Id
#GeneratedValue
protected Long gid;
#ManyToOne(fetch = FetchType.LAZY)
protected Calk calk;
public Long getGid(){
return gid;
}
public void setGid(Long gid){
this.gid = gid;
}
#JsonIgnore
public Calk getCalk(){
return calk;
}
public void setCalk(Calk calk){
this.calk = calk;
}
}
Now I have a class that extends from BaseLayer.java as follow:
PointLayer.java:
#Entity
#DiscriminatorValue("PointDiscriminator")
public class PointLayer extends BaseLayer{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now I create a json as follow and then send it to a controller:
{"layer": "point", "calk":{"id":1}, "name": "itsme"}
Now the controller defines as follow:
#RequestMapping("\test")
public String test(#RequestBody BaseLayer baseLayer){
System.out.println(baseLayer.getName());// this print "itsme"
Calk calk = baseLayer.getCalk();//it return null
if(calk == null)
return "its null";
else
return "its not null";
}
when we call the controller it return its not null. The calk should not be null.
Where is the problem?
Update:
When I remove #JsonIgnore at getCalk, It work fine. But Why? I want to ignore getCalk but NOT ignore setCalk.
#JsonIgnore in follow:
#JsonIgnore
public List<BaseLayer> getBaseLayer() {
return baseLayer;
}
set Ignore to following by default:
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}
You must add #JsonProperty("baseLayer") On top of set function as follow:
#JsonProperty("baseLayer")
public void setBaseLayer(List<BaseLayer> baseLayer) {
this.baseLayer = baseLayer;
}

DTOs and entities which implements the same interface

I have the next maven projects:
project-model : I have JPA entities
project-rest : Spring data, spring rest based on spring boot
project-client : Jersey clients to consume the rest services
project-web : Only jsf web application
project-desktop : Java Fx desktop application
project-android : Mobile application which consumes my Rest web services.
I'm planing to remove the JPA entities from the project-model and place there only DTO's pojos and interfaces and place my JPA entities in the rest project in order to remove the jpa dependencies from the project-model. This is because I don't want to have JPA dependencies in the project-android, project-web and project-desktop.
I was thinking to follow the next schema:
#JsonSerialize(as=CountryDto.class)
#JsonDeserialize(as=CountryDto.class)
public interface ICountry extends Serializable
{}
#Entity
#Table(name = "COUNTRY")
#JsonSerialize(as=Country.class)
#JsonDeserialize(as=Country.class)
public class Country implements ICountry
{}
public class CountryDto implements ICountry
{}
And if I need to convert from Entities to DTO's use mapstruct or Selma.
But I'm not sure if this is the best practice because I have problems in my code like the next:
#JsonSerialize(as=CityDto.class)
#JsonDeserialize(as=CityDto.class)
public interface ICity extends Serializable
{
public Integer getIdCity();
public void setIdCity(Integer idCity);
public String getName();
public void setName(String name);
public ICountry getCountryId();
public void setCountryId(ICountry countryId);
}
public class CityDto implements ICity
{
private static final long serialVersionUID = -6960160473351421716L;
private Integer idCity;
private String name;
private CountryDto countryId;
public CityDto()
{
// TODO Auto-generated constructor stub
}
public CityDto(Integer idCity, String name, CountryDto countryId)
{
super();
this.idCity = idCity;
this.name = name;
this.countryId = countryId;
}
public CityDto(Integer idCity, String name)
{
super();
this.idCity = idCity;
this.name = name;
}
#Override
public Integer getIdCity()
{
return idCity;
}
#Override
public void setIdCity(Integer idCity)
{
this.idCity = idCity;
}
#Override
public String getName()
{
return name;
}
#Override
public void setName(String name)
{
this.name = name;
}
#Override
public ICountry getCountryId()
{
return countryId;
}
#Override
public void setCountryId(ICountry countryId)
{
this.countryId = (CountryDto) countryId;
}
}
#Entity
#Table(name = "CITY")
#JsonSerialize(as=City.class)
#JsonDeserialize(as=City.class)
public class City implements ICity
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_CITY")
private Integer idCity;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "NAME")
private String name;
#JoinColumn(name = "COUNTRY_ID", referencedColumnName = "ID_COUNTRY")
#ManyToOne(optional = false)
private Country countryId;
private static final long serialVersionUID = 1L;
public City()
{
}
public City(Integer idCity)
{
this.idCity = idCity;
}
public City(Integer idCity, String name)
{
this.idCity = idCity;
this.name = name;
}
#Override
public Integer getIdCity()
{
return idCity;
}
#Override
public void setIdCity(Integer idCity)
{
this.idCity = idCity;
}
#Override
public String getName()
{
return name;
}
#Override
public void setName(String name)
{
this.name = name;
}
#Override
public ICountry getCountryId()
{
return countryId;
}
#Override
public void setCountryId(ICountry countryId)
{
this.countryId = (Country) countryId;
}
#Override
public int hashCode()
{
int hash = 0;
hash += (idCity != null ? idCity.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object)
{
// TODO: Warning - this method won't work in the case the id fields are
// not set
if (!(object instanceof City))
{
return false;
}
City other = (City) object;
if ((this.idCity == null && other.idCity != null) || (this.idCity != null && !this.idCity.equals(other.idCity)))
{
return false;
}
return true;
}
#Override
public String toString()
{
return "com.neology.ebreeder.model.entities.City[ idCity=" + idCity + " ]";
}
}
And as You can see in the entity I have getters and setters using the shared interface, and I think that It could provoke problems, I thought to override the getters using the entity but I can't override the setters.
I cant do this:
#Override
public Country getCountryId()
{
return countryId;
}
But I can't do this :
#Override
public void setCountryId(Country countryId)
{
this.countryId = (Country) countryId;
}
Do you see a better solution or could you give me your point of view :)
thanks
Based on past experience, I do not think it is a good idea to use an interface that is shared between the DTO model and the JPA model.
You are in essence tightly coupling your DTO model to your JPA model with this approach.
I would rather have them loosely coupled and use a separate framework to copy between these two models. This will need to be powered by a meta model (could be derived from JPA) to walk and copy the data from one model to another based on the getters and setters.

Categories