SpringMVC #JsonDeserialize doesn't work - spring-mvc

I got a very simple POJO like below:
#Entity
#Table(name = "people")
public class People(){
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer peopleId;
private Date birthday;
#JsonDeserialize(using = DateDeserializer.class)
public void setBirthday(Date birthday){
this.birthday = birthday;
}
}
DateDeserializer:
public class DateDeserializer extends JsonDeserializer<Date> {
#Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
System.out.print("abc2222222222222222222222222222");
return new Date();
}
}
However this deserializer never be invoked at all, I tested #JSonSerializer which works perfectly. is there anything I did wrongly or missed something?

Related

Spring JPA: Adding an entity with current user ID as foreign key

I'm using a Thymeleaf HTML registration form and simple save/update method to save/update a 'dish' object to a mySQL database. Restaurant Id is a foreign key for the 'dish' but using the below methods it saves as 'null',
I would like to make it so that the Restaurant id of the currently logged in restaurant owner saves automatically when they add a dish.
Is there an uncomplicated way to do this? The closest tutorial I've found on Youtube involves using JSON requests in Postman and I've had issue adapting that to a HTML registration form in the past.
I'm quite new to all of this so any help would be very much appreciated!
See Dish class:
package com.bron.demoJPA.appuser;
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#ToString(exclude = "reqlist")
public class Dish {
#Id
#SequenceGenerator(name = "dish_sequence", sequenceName = "dish_sequence", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dish_sequence")
#Column(name = "dish_Id")
private Long dishId;
#Column(name = "dish_name")
private String dname;
#Column(name = "dish_description")
private String description;
#Column(name = "dish_price")
private double price;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "Rest_ID", referencedColumnName = "Rest_ID")
private AppUser app;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "dish_requirment_mapping", joinColumns = #JoinColumn(name = "dish_Id", referencedColumnName = "dish_Id"), inverseJoinColumns = #JoinColumn(name = "Require_ID", referencedColumnName = "Require_ID"))
private List<Requirments> reqlist;
public void addRequirments(Requirments req) {
if (reqlist == null)
reqlist = new ArrayList<>();
reqlist.add(req);
}
}
See AppUser(restaurant owner) Class
#Column(name = "Rest_Password")
private String password;
#Column(name = "Rest_Email_Address")
private String email;
#Enumerated(EnumType.STRING)
private AppUserRole appUserRole;
private Boolean locked = false;
// don't enable user until email verification
private Boolean enabled = false;
public AppUser(String restname, String email, String pass, AppUserRole app) {
this.restaurantName = restname;
this.email = email;
this.password = pass;
this.appUserRole = app;
}
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(appUserRole.name());
return Collections.singletonList(authority);
}
#Override
public String getUsername() {
return email;
}
#Override
public String getPassword() {
return password;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return !locked;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "openingHourID", referencedColumnName = "OpeningHour_ID")
private OpeningHour opening;
}
See Controller class:
package com.bron.demoJPA.conroller;
#Controller
public class DishController {
//display list of employees
#Autowired
private DishService dishService;
#GetMapping("/dish")
public String viewHomePage(Model model) {
model.addAttribute("listDish", dishService.getAllDish());
return "index";
}
#GetMapping("/showNewDishForm")
public String showNewDishForm(Model model) {
// Create model attribute to bind form data
Dish dish = new Dish();
model.addAttribute("dish", dish);
return "new_dish";
}
#PostMapping("/saveDish")
public String saveDish(#ModelAttribute("dish") Dish dish) {
// save dish to database
dishService.saveDish(dish);
return "redirect:/dish";
}
#GetMapping("/showFormForUpdate/{dishId}")
public String showFormForUpdate(#PathVariable(value = "dishId") long dishId, Model model) {
// get dish from service
Dish dish = dishService.getDishByDishId(dishId);
// set dish as model to pre-populate the form data
model.addAttribute("dish", dish);
return "update_dish";
}
}
See Service implementation
package com.bron.demoJPA.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bron.demoJPA.appuser.Dish;
import com.bron.demoJPA.repository.DishRepository;
#Service
public class DishServiceImpl implements DishService {
#Autowired
private DishRepository dishRepository;
#Override
public List<Dish> getAllDish() {
return dishRepository.findAll();
}
#Override
public void saveDish(Dish dish) {
this.dishRepository.save(dish);
}
#Override
public Dish getDishByDishId(long dishId) {
Optional<Dish> optional = dishRepository.findById(dishId);
Dish dish = null;
if (optional.isPresent()) {
dish = optional.get();
} else {
throw new RuntimeException("Dish not found for: " + dishId);
}
return dish;
}
}
See Service class
public interface DishService {
List<Dish> getAllDish();
void saveDish(Dish dish);
Dish getDishByDishId(long dishId);
}
Can you make sure Dish's "app" attribute is being set correctly before trying to save it?
If it's null or it's a brand new instance of AppUser class it makes sense that when trying to match and persist it ends up on null.
Greetings!

How to preserve HttpServletRequest autowiring when testing with SpringMVC Mockito and PowerMockito

Hi I'm trying to write some tests with Mockito and PowerMockito (I need to mock private methods) for a rest service written with SpringMVC and I'm facing the following issue
This is the semplified version of the controller
#Controller
#RequestMapping(value = "/test")
public class SimpleController {
#Autowired
private HttpServletRequest httpRequest;
#RequestMapping(value = "/simpleservice", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
#ResponseBody
public SimpleServiceResponse simpleService(#RequestBody SimpleServiceRequest simpleServiceRequest, HttpServletRequest httpServletRequest) {
SimpleServiceResponse simpleServiceResponse=new SimpleServiceResponse(simpleServiceRequest.getValue());
httpRequest.getHeader("Header");
return simpleServiceResponse;
}
}
and this is the correspoding test class
#WebAppConfiguration
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:WebApplicationContext.xml","classpath:SimpleApplicationContext.xml"})
#PrepareForTest(WebController.class)
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class TestSimpleControllerMockito {
private Logger logger = LoggerFactory.getLogger(TestSimpleControllerMockito.class.getName());
private ObjectMapper objectMapper= new ObjectMapper();
#InjectMocks
private SimpleController controller;
#Test
public void testSimpleService() throws Exception {
MockitoAnnotations.initMocks(this);
SimpleService mockedSimple = mock(SimpleService.class);
when(mockedSimple.doSimpleService(any(SimpleServiceRequest.class))).thenReturn(new SimpleServiceResponse("MockMock"));
SimpleController mockedController=PowerMockito.spy(controller);
SimpleServiceRequest simpleServiceRequest= new SimpleServiceRequest("ciao");
String requestAsStr=objectMapper.writeValueAsString(simpleServiceRequest);
MockMvc mMockMvc=MockMvcBuilders.standaloneSetup(mockedController).build();
MvcResult result= mMockMvc.perform(post("/test/simpleservice").content(requestAsStr).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
String content = result.getResponse().getContentAsString();
SimpleServiceResponse simpleServiceResponse=objectMapper.readValue(content,SimpleServiceResponse.class);
Assert.assertEquals("MockMockMockedSessionManager",simpleServiceResponse.getValue());
}
}
When running the test case I got a NullPointerEception on httpRequest.getHeader("Header");
My guess is that using the #InjectMocks annotation and then using
SimpleController mockedController=PowerMockito.spy(controller);
is the cause of the NullPointerException. I don't know how to preserve the #Autowire annotation processing on the controller Object. I already found a workaround, but it requires to write some redundant code.
Is there a way to make the #autowired annotation work?
Thanks a lot.
P.S.
the SimpleServiceXXX classes are like this one:
public class SimpleServiceResponse {
private String value;
public SimpleServiceResponse() {
}
public SimpleServiceResponse(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

Custom #Id class for Spring Data Redis

I am trying to convert / serialize the #Id field (which is not a string) of the model class but keep getting this error. The custom ID class just concatenates two values with a colon, e.g. aaaa:2345.
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [MyIdClass] to type [byte[]]
This is my model class.
#RedisHash("alert")
public class MyClass implements Serializable
{
public static class MyIdClass
{
public String userId;
public Long sessionExpiry;
public MyIdClass()
{
}
public MyIdClass(String id, Long ex)
{
userId = id;
sessionExpiry = ex;
}
}
public static class MyIdClassSerializer implements RedisSerializer<MyIdClass>
{
#Nullable
#Override
public byte[] serialize(#Nullable MyIdClass uid) throws SerializationException
{
return String.format("%s:%d", uid.userId, uid.sessionExpiry).getBytes();
}
#Nullable
#Override
public MyIdClass deserialize(#Nullable byte[] bytes) throws SerializationException
{
String[] t = new String(bytes).split(":");
return new MyIdClass(t[0], Long.parseLong(t[1]));
}
}
#Component
#ReadingConverter
public static class MyIdClassReader implements Converter<byte[], MyIdClass>
{
#Nullable
#Override
public MyIdClass convert(byte[] source)
{
String[] t = new String(source).split(":");
return new MyIdClass(t[0], Long.parseLong(t[1]));
}
}
#Component
#WritingConverter
public static class MyIdClassWriter implements Converter<MyIdClass, byte[]>
{
#Nullable
#Override
public byte[] convert(MyIdClass uid)
{
return String.format("%s:%d", uid.userId, uid.sessionExpiry).getBytes();
}
}
/**
* User ID
* Key := 'alert:' userId ':' sessionExpiry
*/
#Id
public MyIdClass id;
public String value;
}
Here's how I'm configuring the RedisTemplate.
#Bean("redisTemplateActivityAlert")
public RedisTemplate<ActivityAlert.UserIdExpiry, ActivityAlert> redisTemplateActivityAlert()
{
RedisTemplate<ActivityAlert.UserIdExpiry, ActivityAlert> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new ActivityAlert.UserIdExpirySerializer());
template.setHashKeySerializer(new ActivityAlert.UserIdExpirySerializer());
return template;
}
I've read other posts about configuring ConversionService or TypeConverter but haven't gone far with them.
add this Bean to your RedisConfiguration :
#Bean
public RedisCustomConversions redisCustomConversions(MyIdClassReader myIdClassReader , MyIdClassWriter myIdClassWriter ) {
return new RedisCustomConversions(Arrays.asList(myIdClassWriter,myIdClassReader));
}

spring MVC LazyInitialisationException

we are working on springMVC java config app. I am facing a problem every time when i trying to view child object properties but getting lazyinitialisationexception no session error. this i am getting on ajax calls also. I know that eager fetching is one solution and Hibernate.initailize(child) is another. But what is the standard way to resolve this?
My entities are like this
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name = "COUNTRY_DETAILS")
public class Country implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Set<State> states;
#Id
#GeneratedValue
#Column(name = "ID", length = 20, nullable = false)
public Long getId() {
return id;
}
public void set Id(Long id) {
this.id = id;
}
#Column(name = "NAME", length = 20, nullable = false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Country() {
super();
// TODO Auto-generated constructor stub
}
public Country(String name) {
super();
this.name = name;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "countryId")
public Set<State> getStates() {
return states;
}
public void setUnits(Set<State> states) {
this.states = states;
}
}
States entity
#Entity
#Table(name = "State_DETAILS")
public class State implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "State_ID", length = 20, nullable = false)
private Long StateId;
#Column(name = "State_NAME", length = 20, nullable = false)
private String StateName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Country_ID", nullable = false, //
foreignKey = #ForeignKey(name = "Country_DETAIL_State_FK") )
private Country countryId;
Public Long getStateId() {
return StateId;
}
public void setStateId(Long StateId) {
this.StateId = StateId;
}
public String getStateName() {
return StateName;
}
public void setStateName(String StateName) {
this.StateName = StateName;
}
public Country getCountryId() {
return countryId;
}
public void setCmdId(Country countryId) {
this.countryId = countryId;
}
public State(Long StateId) {
super();
this.StateId = StateId;
}
public State() {
super();
// TODO Auto-generated constructor stub
}
}
My Controller
This is my controler
#RequestMapping(value = "/findStatesByCountry", method = RequestMethod.GET)
public #ResponseBody List<State> findAllStateByCountryId() {
Country c=new Country();
c.setId((long) 1);
List<State> states=stateService.getStatesByCommand(c);
return units;
}
Error I am getting is
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not initialize proxy - no Session
I want to show in view like country.state.stateId ,state.country.name e.t.c .
How to resolve this type of situation?
Eager is the not the solution i want to use
Found the answer finally.OpenEMInViewFilter is the solution..I tried the following and working fine...
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I have used interceptor also..
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping
path="/resources/**"/>
<bean class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor"
/>
</mvc:interceptor>
</mvc:interceptors>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
it is working fine now and able to fetch associations in views.Let me know if any cons in this type of usage...
Thanx

How to use Jackson to deserialise list in java?

My Java Class is
public class User {
private List<UserInfo> userInfoList;
public class UserInfo {
private String id;
}
}
Let's assume it has getter, setter method.
json is
{"userInfoList" : [{"id":"a", "id":"b"}]}
I tried to deserialize it like below.
objectMapper.readValue(json, User.class);
But it throws error.
Can not construct instance of User$UserInfoList: no suitable constructor found
How to deserialize it?
I think you should make UserInfo static. Jackson cannot construct the UserInfo class.
I tried with that change and it works for me :
public class User {
private List<UserInfo> userInfoList;
public static class UserInfo {
private String id;
public UserInfo() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
public List<UserInfo> getUserInfoList() {
return userInfoList;
}
public void setUserInfoList(List<UserInfo> userInfoList) {
this.userInfoList = userInfoList;
}
}
And :
public class App {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
User.UserInfo ui1 = new User.UserInfo();
ui1.setId("a");
User.UserInfo ui2 = new User.UserInfo();
ui2.setId("b");
List<User.UserInfo> userInfoList = new ArrayList<User.UserInfo>();
userInfoList.add(ui1);
userInfoList.add(ui2);
User user = new User();
user.setUserInfoList(userInfoList);
System.out.println(mapper.writeValueAsString(user));
user = mapper.readValue(mapper.writeValueAsString(user), User.class);
}
}

Resources