Spring controller inheritance and linked requestbody deserealization problems - spring-mvc

My objectmapper not working when I use spring controller & class for requestbody inheritation .
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type", visible = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = RecipeVersion.class, name = "recipe"),
#JsonSubTypes.Type(value = DietVersion.class, name = "diet"),
})
public interface DocumentVersion {
Info getInfo();
void setInfo(Info info);
}
and also
#Data
public class DietVersion implements DocumentVersion {
private LocalizedText warnings;
private List<DietDay> days = new LinkedList<>();
private Info info = new Info();
private String getType() {
return "diet";
}
}
Ok. I have BaseController for diets and recipes
abstract public class BaseController<T extends Document<V>, V extends DocumentVersion> {
abstract protected BaseService<T, V> getService();
#PostMapping("/{docId}/version/last")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void saveVersion(#PathVariable("docId") String docId, #RequestBody V version, Authentication authentication) {
getService().replaceLastVersion(docId, version, authentication);
}
}
and some realizations. example for diet
#Controller
#RequestMapping("/diet")
public class DietController extends BaseController<Diet, DietVersion> {
private final DietService dietService;
#Autowired
public DietController(DietService dietService) {
this.dietService = dietService;
}
#Override
protected DietService getService() {
return dietService;
}
#Override
public void saveVersion(String docId, DietVersion version, Authentication authentication) {
super.saveVersion(docId, version, authentication);
}
}
But when I send json with info, days, type ('diet') to '/diet/1/version/last' then I see in debug mode that my DietVersion pure clear and has no any data. Why ?
How to change settings for objectmapper ?

what if you provide all this in your DietController class.
public void saveVersion(#PathVariable("docId") String docId, #RequestBody V version, Authentication authentication){

Related

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));
}

Error While Fetching Data from Corda Custom Tables

How to fetch data from corda Custom tables?
my sample code is as follows :-
Api layer -- getIous() method
{
Field attributeValue=IOUSchemaV1.PersistentIOU.class.getDeclaredField("value");
CriteriaExpression currencyIndex = Builder.equal(attributeValue, "12");
QueryCriteria.VaultCustomQueryCriteria criteria = new
QueryCriteria.VaultCustomQueryCriteria(currencyIndex);
vaultStates = services.vaultQueryByCriteria(criteria,IOUState.class);
}
In ExamplePlugin I added below code for schema registration
public class ExamplePlugin extends CordaPluginRegistry implements
WebServerPluginRegistry
{
#NotNull
#Override
public Set<MappedSchema> getRequiredSchemas()
{
Set<MappedSchema> requiredSchemas = new HashSet<>();
requiredSchemas.add(new IOUSchemaV1());
return requiredSchemas;
}
}
My Schema classes are ---
public final class IOUSchema {
}
#CordaSerializable
public class IOUSchemaV1 extends MappedSchema
{
public IOUSchemaV1() {
super(IOUSchema.class, 1, ImmutableList.of(PersistentIOU.class));
}
#Entity
#Table(name = "iou_states")
public static class PersistentIOU extends PersistentState {
#Column(name = "sender_name") private final String senderName;
#Column(name = "recipient_name") private final String recipientName;
#Column(name = "value") private final int value;
public PersistentIOU(String senderName, String recipientName, int value) {
this.senderName = senderName;
this.recipientName = recipientName;
this.value = value;
}
public String getSenderName() {
return senderName;
}
public String getRecipientName() {
return recipientName;
}
public int getValue() {
return value;
}
}
}
my state has :-
public class IOUState implements LinearState, QueryableState
{
--- some code goes here and below methods as well.---
#Override
public PersistentState generateMappedObject(MappedSchema schema) {
if (schema instanceof IOUSchemaV1) {
return new IOUSchemaV1.PersistentIOU(
this.sender.getName().toString(),
this.recipient.getName().toString(),
this.iou.getValue());
} else {
throw new IllegalArgumentException("Unrecognised schema $schema");
}
}
#Override
public Iterable<MappedSchema> supportedSchemas() {
return ImmutableList.of(new IOUSchemaV1());
}
}
But all the time i am getting below exception.
Caused by: net.corda.core.node.services.VaultQueryException:
Please register the entity 'com.example.schema.IOUSchemaV1' class in your CorDapp's CordaPluginRegistry configuration (requiredSchemas attribute)
and ensure you have declared (in supportedSchemas()) and mapped (in generateMappedObject())
the schema in the associated contract state's QueryableState interface implementation.
Can anyone please help to resolve this.
Try deleting implements WebServerPluginRegistry from your plugin declaration.

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);
}
}

Spring MVC doesn't handle the error came from hibernate validator

I create form and controller this form have some validation constrains using Hibernate validator. I face problem when starting test the validation constrains but I got Blue Exception page with the attributemodel with the rejected.
This the configuration
#Configuration
#ComponentScan(basePackages = {"com.whatever.core.web"})
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurationSupport {
private static final String MESSAGE_SOURCE = "/WEB-INF/classes/messages";
private static final String TILES = "/WEB-INF/tiles/tiles.xml";
private static final String VIEWS = "/WEB-INF/views/**/views.xml";
private static final String RESOURCES_HANDLER = "/resources/";
private static final String RESOURCES_LOCATION = RESOURCES_HANDLER + "**";
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
requestMappingHandlerMapping.setUseTrailingSlashMatch(false);
return requestMappingHandlerMapping;
}
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJacksonHttpMessageConverter());
}
#Bean(name = "messageSource")
public MessageSource configureMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename(MESSAGE_SOURCE);
messageSource.setCacheSeconds(5);
return messageSource;
}
#Bean
public TilesViewResolver configureTilesViewResolver() {
return new TilesViewResolver();
}
#Bean
public TilesConfigurer configureTilesConfigurer() {
TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions(new String[] {TILES, VIEWS});
return configurer;
}
#Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(configureMessageSource());
return validator;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(RESOURCES_HANDLER).addResourceLocations(RESOURCES_LOCATION);
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
and the controller here
if(result.hasErrors()){
return null; OR "view name"
}
User user = new User();
user.setUsername(userModel.getUsername());
user.setFirstName(userModel.getFirstName());
user.setLastName(userModel.getLastName());
user.setGender(userModel.getGender());
user.setLocation(userModel.getLocation());
user.setPassword(passwordEncoder.encodePassword(userModel.getPassword(),null));
userRepository.save(user);
doAutoLogin(userModel.getUsername(),userModel.getPassword(),request);
return "redirect:/home";
NOTE: I use springMVC, spring security, tiles, and hibernate validator
I used SpringMVC with hibernate validator with XML configuration and portal environment and work fine I don't know what the wrong here!!
I Found the issue! the signature of the method controller should be like this
public String signup(#ModelAttribute("userModel") #Valid SignupForm userModel,BindingResult result,HttpServletRequest request,HttpServletResponse response,ModelMap model)
as what I read in sprinsource forum, the BindingResult should follow the modelAttribute and work find. I didn't find any official documentation for this but its work now.
to see the thread of springsource forum check this link http://forum.springsource.org/showthread.php?85815-BindException-Thrown-on-bind-errors-(instead-of-returning-errors-to-controller-method

Resources