hibernate projection NumberFormatException for input string - spring

I am using Spring MVC + Hibernate
Generic Dao
// getAll
#SuppressWarnings("unchecked")
public <T> List<T> getAll(Class<T> entityClass) throws DataAccessException {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(entityClass);
return criteria.list();
}
#Controller
#RequestMapping(value = "/genCompanyInfoUpdate", method = RequestMethod.POST)
public String genCompanyInfoUpdate(Model model) {
List<GenCountryModel> countryList=pt.getAll(GenCountryModel.class);
List<GenCurrencyModel> currencyList=pt.getAll(GenCurrencyModel.class);
GenCompanyInfoModel companyInfo=pt.getById(GenCompanyInfoModel.class, 1);
model.addAttribute("countryList", countryList);
model.addAttribute("currencyList", currencyList);
model.addAttribute("companyInfo", companyInfo);
return "gen/genCompanyInfoUpdate";
}
JSP
<c:if test="${not empty currencyList}">
<c:forEach items="${currencyList}" var="get" varStatus="counter">
<ct:Options setValue="${get.id}" setName="${get.isoCode}" selected="${companyInfo.genCurrencyModel.id}" setState="1" />
</c:forEach>
</c:if>
All working well but when I change and use Projection in Method as the following , then it give exception
java.lang.numberformatexception for input string id
java.lang.numberformatexception for input string isoCode
Changes: ProjectionList use in Method
#SuppressWarnings("unchecked")
public <T> List<T> getAll(Class<T> entityClass, String[] nameList) throws DataAccessException {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(entityClass);
ProjectionList pl = Projections.projectionList();
for (int i=0; i<nameList.length; i++) {
pl.add(Projections.property(nameList[i].toString()));
}
criteria.setProjection(pl);
return criteria.list();
}
Changes in #Controller passing List [GenCurrencyModel]
#RequestMapping(value = "/genCompanyInfoUpdate", method = RequestMethod.POST)
public String genCompanyInfoUpdate(Model model) {
String []list={"id","isoCode"};
List<GenCountryModel> countryList=pt.getAll(GenCountryModel.class);
List<GenCurrencyModel> currencyList=pt.getAll(GenCurrencyModel.class,list);
GenCompanyInfoModel companyInfo=pt.getById(GenCompanyInfoModel.class, 1);
model.addAttribute("countryList", countryList);
model.addAttribute("currencyList", currencyList);
model.addAttribute("companyInfo", companyInfo);
return "gen/genCompanyInfoUpdate";
}
Same JSP
<c:if test="${not empty currencyList}">
<c:forEach items="${currencyList}" var="get" varStatus="counter">
<ct:Options setValue="${get.id}" setName="${get.isoCode}" selected="${companyInfo.genCurrencyModel.id}" setState="1" />
</c:forEach>
</c:if>
GenCurrencyModel
public class GenCurrencyModel implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "CURRENCYID")
#GeneratedValue
private long id;
#Column(name = "CODE")
private String currencyCode;
#Column(name = "DESCRIPTION")
private String currencyDesc;
#Column(name = "ISACTIVE")
private int isActive;
#Column(name = "MADELETE")
private int markAsDelete;
#Column(name = "ISOCODE")
private String isoCode;
#Column(name = "CURRENCYUNIT")
private String currencyUnit;
#Column(name = "CONNECTOR")
private String connector;
#Column(name = "SUBUNIT")
private String subUnit;
#Column(name = "RECENTUSERID")
private long recentUserId;
#Column(name = "RECENTUSERIP")
private String recentUserIp;
#Column(name = "DATETIME")
private Date dateTime;
#Column(name = "ISUPDATED")
private int isUpdated;
private GenCompanyInfoModel genCompanyInfoModel;
public GenCurrencyModel() {
super();
}
//Getter Setter
}
I check the query from log file . it successfully execute
and when I remove the following line from jsp page, then there is no any exception
<ct:Options setValue="${get.id}" setName="${get.isoCode}"
Note: ct:Options is a custom JSP tag, that just print values, nothing special
After Projection the result of query is as follow
Hibernate: select this_.CURRENCYID as y0_, this_.ISOCODE as y1_ from GENCURRENCY this_
and both returning the list , and I have check both of size(), the size is also same !
Update me !

Typically, when using a projection list of specific properties in Hibernate, you won't be able to cast the query result as an entity type, at least not in the older versions of Hibernate I'm familiar with (i.e. 3.2.x). Instead, the default return type will be a List<Object[]> (when calling Criteria#list), where each array represents a tuple of the properties you specified in the projection list. (You can tell Hibernate to change the return type by giving the Criteria a ResultTransformer, but that may cause more confusion.) So instead of expecting partially-hydrated entities of type T and calling its getter methods (via JSTL expression), expect an array of Objects and get each property value by index (based on the order of the properties in the projection list).
Otherwise, it appears that you're passing the string values "id" and "isoCode" to your ct tag library (instead of the id and isoCode field values that you want), which I assume is expecting strings that can be parsed into numbers using something like Integer#parseInt(String), and this is causing the NumberFormatExceptions.
If this doesn't help, can you please provide more information? Specifically:
What are the property names you're specifying in the projection list?
What object types are those properties mapped as in the entity class? Providing the full entity mapping would help.
Is the ct:Options a custom JSP tag? If so, can you provide the logic of the tag class?

Related

JPA calling default constructor even during POST request

I didn't had a default constructor in my entity class in the beginning. Eventually found out that JPA requires a default constructor in entity class so I made one.
After adding the default constructor, even during post requests, JPA keeps calling default constructor which leads to incorrect initialisation of properties. For example, if you see the property called availableSeats, it is initialised to 100, but during post request only default constructor is called which leads to initialisation of availableSeats to 0.
This is extremely weird and I don't understand what am I doing wrong here.
#Entity
public class Flight {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank(message = "Airline Name cannot be blank!")
private String airlineName;
#NotBlank(message = "From-Location cannot be blank!")
private String fromLocation;
#NotBlank(message = "To-Location cannot be blank!")
private String toLocation;
#NotBlank(message = "Airport Gate Number cannot be blank")
private String gateNumber;
// #NotBlank(message = "Boarding time cannot be blank")
private ZonedDateTime dateTimeZone;
private static final int INITIAL_SEAT_CAPACITY = 100;
private int availableSeats;
// constructor should not be able to set id
public Flight(Long id, String airlineName, String fromLocation, String toLocation, String gateNumber, ZonedDateTime dateTimeZone, int availableSeats) {
this.id = id;
this.airlineName = airlineName;
this.fromLocation = fromLocation;
this.toLocation = toLocation;
this.gateNumber = gateNumber;
this.dateTimeZone = dateTimeZone;
// setting up initial number of available seats
this.availableSeats = INITIAL_SEAT_CAPACITY;
}
public Flight(){
}
// getters and setters
}
Also adding FlightController.java code here
#RestController
#RequestMapping("/api/flights")
public class FlightController {
#Autowired
FlightService flightService;
#GetMapping(value = "/")
public ResponseEntity<List<Flight>> getAllFlights(){
return flightService.getAllFlights();
}
#PostMapping(value = "/")
public ResponseEntity<String> createFlight(#Valid #RequestBody Flight flight){
return flightService.createFlight(flight);
}
#GetMapping(value = "/{id}")
public ResponseEntity<Flight> getFlightById(#PathVariable Long id){
return flightService.getFlightById(id);
}
#DeleteMapping(value = "/{id}")
public ResponseEntity<String> deleteFlight(#PathVariable Long id){
return flightService.deleteFlight(id);
}
}
Spring's controller uses default(zero argument) constructor for object creation and then uses it's setter methods for setting the values in the object. You cannot expect for spring to use parameterized constructor.
So if you need to set some default values then do it in zero argument constructor.
As #grigouille pointed out in the comments, JPA only uses default constructor. Hence, availableSeats should have been initialised in the default constructor too.

Spring Boot Entity model member converter

Here my problem, I have to store serialized website's cookie information in DB, and I tried to write a simple PesistentConverter to it can be convert Map to String and vice-versa. But the IDE show a warning about this:
'Basic' attribute type should not be a map
Here my Entity:
#Entity
#Table(name = "website")
public class Website implements Serializable {
#Id
#Column(name = "name", length = 16, nullable = false)
#NotNull
private String name;
#Column(name = "serialized_cookie_map", nullable = false, length = 2048)
#Convert(converter = CookieMapPersistenceConverter.class)
#NotNull
private Map<String,String> serializedCookieMap;
...
}
CookieMapPersistenceConverter:
public class CookieMapPersistenceConverter implements AttributeConverter<Map<String, String>, String> {
#Override
public String convertToDatabaseColumn(Map<String, String> stringStringMap) {
return stringStringMap.toString();
}
#Override
public Map<String, String> convertToEntityAttribute(String s) {
ObjectMapper mapper = new ObjectMapper();
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, String.class);
HashMap<String,String> convertedMap = null;
try {
convertedMap = mapper.readValue(s, mapType);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return convertedMap;
}
}
I'm using the 2.6.3 version of Spring Boot.
Many thanks your time!
According to this:
Any attributes that have no other annotations and do not reference
other entities will be automatically mapped as basic.
and according to the table from the above link map is not a basic type. so IDE is right about
'Basic' attribute type should not be a map
I suggest try the following approach to see it satisfies your requirements or not.
#Id
#Column(name = "id", length = 16, nullable = false)
#NotNull
private String id;
#ElementCollection
#MapKeyColumn(name="property")
#Column(name="value")
#CollectionTable(name="cookies", joinColumns=#JoinColumn(name="id"))
#NotNull
private Map<String,String> serializedCookieMap;
//setter and getter
and the code for repositry:
#Repository
public interface WebsiteRepository extends CrudRepository<Website, String> {}
code I did for test:
Website w = new Website();
w.setId("id");
Map<String, String> m = new HashMap<>();
m.put("key1", "value1");
m.put("key2", "value2");
m.put("key3", "value3");
w.setSerializedCookieMap(m);
repo.save(w);
which creates two table named WEBSITE and COOKIES and the content of each is like this:
WEBSITES:
ID
id
and:
COOKIES:
ID VALUE PROPERTY
id value1 key1
id value2 key2
id value3 key3
if you insist to store Serialized version of map take a look at this
I have tried same thing in my project (with same version of spring boot). I did not notice any warning.
But here are some suggestions...
The field you have annotated #convert not meant to be persisted in DB. So instead of #column try using #Transient.
You can also try using #Type( type = "json" ) instead of #convert.
Also this can be possibly issue with IDE, so just to ignore it as a
warning you can use #SuppressWarnings("JpaAttributeTypeInspection") annotation.

MyBatis #Many / Spring-Boot

I'm beginner (sorry for my bad explanation, feel free to correct me) in MyBatis Spring-Boot, I have problem to understand and make it works #Many
I'm using 3 layer logic programming (Presentation Layer, Service Layer, Data Layer)
Thanks for your help :)
I have 3 Tables (it's TB_Products and not TB_Product as on the screenshot):
I would like to get data form table TB_Users and TB_Products to "put" it in DTO
I create 4 java object class SearchEntity, ProductEntity (for Data layer)
I create an interface SearchRepositoryMapper.
I also create a SearchService interface and SearchServiceImpl as well.
Java object class:
SearchEntity
public class SearchEntity implements Serializable{
private static final long serialVersionUID = -9143930742617602050L;
private String id;
private String firstName;
private String lastName;
private List<ProductEntity> products;
// Getters and Setters code .....
}
ProductEntity
public class ProductEntity implements Serializable{
private static final long serialVersionUID = -6525703679290992635L;
private String id;
private String productId;
private String product;
private String number;
private String date;
private String description;
// Getters and Setters code .....
}
SearchRepositoryMapper
public interface SearchRepositoryMapper {
// Get some fields from TB_Users and all fields from TB_Products
#Select("SELECT * FROM TB_Users WHERE id = #{id}")
#Results({
#Result(property = "id", column ="id"),
#Result(property = "firstName", column = "firstName"),
#Result(property = "lastName", column= "lastName"),
#Result(property = "products", javaType = List.class, column="id",
many = #Many(select = "getProductIdByUserId"))})
public SearchEntity findAllInfoByUserId(#Param("id") int id);
#Select("SELECT *, productId FROM TB_Products WHERE productId = #{id}")
public ArrayList<ProductEntity> getProductIdByUserId(#Param("id") int id);
// Find id by uderId and return null if it doesn't exist
#Select("SELECT id FROM TB_Users WHERE userId = #{userId}")
int findIdByUserId(#Param("userId") String userId);
}
SearchServiceImpl
#Service
public class SearchServiceImpl implements SearchService {
#Autowired
SearchRepositoryMapper searchRepository;
#Override
public SearchDto getAllInfoByUserId(String id) {
SearchDto returnValue = new SearchDto(); // Init returnValue as SearchDto
int searchId = searchRepository.findIdByUserId(id); // Init searchId with the TB_Users id
SearchEntity searchEntity = searchRepository.findAllInfoByUserId(searchId);
BeanUtils.copyProperties(searchEntity, returnValue);
return returnValue;
}
}
So when I execute the code and do a GET request I get this error message:
{
"message": "nested exception is org.apache.ibatis.executor.ExecutorException: Statement returned more than one row, where no more than one was expected."
}
I found out that come from the mapper and SearchEntity searchEntity = searchRepository.findAllInfoByUserId(searchId);
But i don't know how to resolve it. The way I wrote the code is wrong
Thanks to correct me
The exception clearly says that the query returns multiple results. Plese verify if the data in the table is correct.

Mixed parameter strategies - use just one of named, positional or JPA-ordinal strategy

I am calling function from Oracle database and facing this Exception:
org.hibernate.engine.query.ParameterRecognitionException: Mixed parameter strategies - use just one of named, positional or JPA-ordinal strategy
This is my User.java entity.
#Entity
#Table(name = "users", schema = "myschema")
#javax.persistence.NamedNativeQuery(name = "getPass", query = "{? call = his.get_abc(:mrno)}", resultClass = User.class, hints = {
#javax.persistence.QueryHint(name = "org.hibernate.callable", value = "true") })
public class User {
#Id
#Column(name = "USERID", nullable = false)
private String userid;
#Column(name = "MRNO")
private String mrno;
private String username;
private String password;
private String fullName;
// Getters and Setters are written.
}
And this is how I am calling this function from my one of Service class.
public boolean validateUser(String mrno, String password) {
String completeMrno = utils.getMedicalRecordNumber(mrno);
EntityManagerFactory factory = Persistence.createEntityManagerFactory("his-dev");
EntityManager entityManager = factory.createEntityManager();
Query query = entityManager.createNamedQuery("getPass"); // <- this line is raising exception.
query.setParameter("mrno",completeMrno);
List<?> results = query.getResultList();
}
So, what changes are required in order to call Oracle Function which returns a String.
Thanks. Let me know if more information is required.
Find below an example how to call the function with JPA:
Object result = entityManager.createNativeQuery("SELECT his.get_abc(:mrno) FROM DUAL")
.setParameter("mrno", completeMrno)
.getSingleResult();
String value = new String(result);

How to search nested object by using Spring Data Solr?

I have two such Java object:
public class PSubject
{
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("name")
private String name;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("type")
private String type;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("uri")
private String uri;
#OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
#IndexedEmbedded
#org.apache.solr.client.solrj.beans.Field("attributes")
private Set<PAttribute> attributes = new HashSet<PAttribute>();
.....
}
#Entity
#Indexed
#Table(name="PAttribute")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class PAttribute extends PEntity
{
private static final long serialVersionUID = 1L;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.YES)
#org.apache.solr.client.solrj.beans.Field("attr_name")
private String name;
#Column
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.YES)
#org.apache.solr.client.solrj.beans.Field("attr_value")
private String value;
.....
}
And my Spring Data Solr query interface:
public interface DerivedSubjectRepository extends SolrCrudRepository<PSubject, String> {
Page<PSubject> findByName(String name, Pageable page);
List<PSubject> findByNameStartingWith(String name);
Page<PSubject> findBy(Pageable page);
#Query("name:*?0* or description:*?0* or type:*?0* or mac_address:*?0* or uri:*?0* or attributes:*?0*")
Page<PSubject> find(String keyword,Pageable page);
#Query("name:*?0* or description:*?0* or type:*?0* or mac_address:*?0* or uri:*?0* or attributes:*?0*")
List<PSubject> find(String keyword);
}
I can search any by name, description, type and mac_address, but can't search any result by attribute.
Update:
For example,when user search "ipod", it's probably means the type of subject or name of subject, or the name of attribute or the value of attribute. And I want get all the matched subject in one request. I know I can search the attribute object in a separate query. But that makes the code in the backend complex.
So, how can I search this nested object?
Update:
I flattened my data:
#Transient
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#org.apache.solr.client.solrj.beans.Field("attrs")
private String attrs;
public String getAttrs() {
return attrs;
}
public void setAttrs(Set<PAttribute> attributes) {
StringBuffer attrs = new StringBuffer();
if(attributes==null) {
attributes = this.getAttributes();
}
for(PAttribute attr:attributes){
attrs.append(attr.getName()+" " + attr.getValue()).append(" ");
}
this.attrs =attrs.toString();
}
The issue is resolved.
IIRC it is not possible to store nested data structures in solr - it depends how you flatten your data to fit into an eg. multivalue field - a little hard not knowing your schema.
see: http://lucene.472066.n3.nabble.com/Possible-to-have-Solr-documents-with-deeply-nested-data-structures-i-e-hashes-within-hashes-td4004285.html
How does the data look like in you index, and did you have a look at the http request sent by spring-data-solr?

Resources