I use orika 1.5.2 . when map data from HashMap to bean with convert String to java.util.Date, I get the Exception:
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
DateToStringConverter also not take effect. But the exception not come out when I map data from Bean A to Bean B.
How can I convert String to Date when I map data from a Map to bean?
code:
public class UserA {
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
#Override
public String toString() {
return "UserA [birthday=" + birthday + "]";
}
}
public static void main(String[] args){
HashMap map = new HashMap();
map.put("birthday", "2014-04-28");
UserA ua = new UserA();
MapperFactory mapF = new DefaultMapperFactory.Builder().mapNulls(false).build();
mapF.getConverterFactory().registerConverter(new DateToStringConverter("yyyy-MM-dd"));
mapF.getMapperFacade().map(map, ua);
}
exception:
Exception
U need Object to Date converter, not DateToStringConverter
user:
#Data
public class UserA {
private Date birthday;
}
add Converter
public class ObjectToDateConverter extends CustomConverter<Object, Date> {
#Override
public Date convert(Object source, Type<? extends Date> destinationType, MappingContext context) {
if (source instanceof String) {
try {
return new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse((String) source);
} catch (ParseException e) {
return null;
}
}
return null;
}
}
test:
#Test
public void testMap(){
HashMap map = new HashMap();
map.put("birthday", "2018-10-14");
UserA ua = new UserA();
MapperFactory mapF = new DefaultMapperFactory.Builder().mapNulls(false).build();
mapF.getConverterFactory().registerConverter(new ObjectToDateConverter());
mapF.getMapperFacade().map(map, ua);
}
Related
I am having some trouble serializing/deserializing my classes below.
My Data class holds a list of other classes.
When I call the serialize/deserialize methods in the Data class, I get the following error:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.amazon.rancor.storage.types.ChildData: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
The error comes from the deserialize method. But I also believe the serialization is not working properly. This is what the serialized Data object looks like:
{childData:[{zipCode:{present:true},countryCode:"US"}]
The Optional field is not being serialized properly even though I have set the objectMapper.registerModule(new Jdk8Module()); field
I can't seem to figure out what I am doing wrong. Maybe I need to change something in ChildData and ChildDataV2 class. But I am not sure what.
Any pointers would be appreciated!
public class Data {
private List<ChildData> childData;
private List<ChildDataV2> childDataV2;
private static ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new Jdk8Module());
}
public Data() { }
#JsonCreator
public Data(#JsonProperty("childData") final List<ChildData> childData,
#JsonProperty("childDataV2") final List<ChildDataV2> childDataV2) {
this.childData = childData;
this.childDataV2 = childDataV2;
}
public List<ChildData> getChildData() {
return childData;
}
public void setChildData(final List<ChildData> childData) {
this.childData = childData;
}
public List<ChildDataV2> getChildDataV2() {
return childDataV2;
}
public void setChildDataV2(final List<ChildDataV2> childDataV2) {
this.childDataV2 = childDataV2;
}
public String serialize() {
try {
return objectMapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to serialize. Data: " + this, e);
}
}
public Data deSerialize(final String data) {
try {
return objectMapper.readValue(data, Data.class);
} catch (IOException e) {
throw new RuntimeException("Failed to deserialize. Data" + data, e);
}
}
}
public class ChildData {
private final String countryCode;
private final Optional<String> zipCode;
public ChildData(final String countryCode, final Optional<String> zipCode) {
this.countryCode = countryCode;
this.zipCode = zipCode;
}
public Optional<String> getZipCode() {
return zipCode;
}
public String getCountryCode() {
return countryCode;
}
}
public class ChildDataV2 extends ChildData {
private final Object struct;
public ChildDataV2(final String cc, final Optional<String> postalCode,
final Object struct) {
super(cc, postalcode);
this.struct = struct;
}
}
The exception is quite clear right? You need to add a default constructor for ChildData or annotate the existing constructor like this:
#JsonCreator
public ChildData(#JsonProperty("countryCode") String countryCode, #JsonProperty("zipCode") Optional<String> zipCode) {
this.countryCode = countryCode;
this.zipCode = zipCode;
}
How can I test one PUT request with Spring Boot??
I have this method:
#RequestMapping(method = RequestMethod.PUT, value = "/")
public NaturezaTitulo save(#RequestBody NaturezaTitulo naturezaTitulo){
return naturezaTituloService.save(naturezaTitulo);
}
and this test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class NaturezaTituloControllerTest {
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
private MockMvc mockMvc;
private HttpMessageConverter mappingJackson2HttpMessageConverter;
private List<NaturezaTitulo> naturezaTituloList = new ArrayList<>();
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
void setConverters(HttpMessageConverter<?>[] converters) {
this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream().filter(
hmc -> hmc instanceof MappingJackson2HttpMessageConverter).findAny().get();
Assert.assertNotNull("the JSON message converter must not be null",
this.mappingJackson2HttpMessageConverter);
}
#Before
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void naturezaTituloNotFound() throws Exception {
mockMvc.perform(get("/naturezatitulo/55ce2dd6222e629f4b8d6fe0"))
.andExpect(status().is4xxClientError());
}
#Test
public void naturezaTituloSave() throws Exception {
NaturezaTitulo naturezaTitulo = new NaturezaTitulo();
naturezaTitulo.setNatureza("Testando");
mockMvc.perform(put("/naturezatitulo/").content(this.json(naturezaTitulo))
.contentType(contentType))
.andExpect(jsonPath("$.id", notNullValue()));
}
protected String json(Object o) throws IOException {
MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
this.mappingJackson2HttpMessageConverter.write(
o, MediaType.APPLICATION_JSON, mockHttpOutputMessage);
return mockHttpOutputMessage.getBodyAsString();
}
}
but I got this error:
java.lang.IllegalArgumentException: json can not be null or empty at
com.jayway.jsonpath.internal.Utils.notEmpty(Utils.java:259)
how can I pass one object from body in Put test?
tks
I am getting the below exception:
Could not find PortableFactory for factory-id: 1
com.hazelcast.nio.serialization.HazelcastSerializationException: Could
not find PortableFactory for factory-id: 1
On the client side I have the following code:
public class ClientTest {
public static void main(String[] args) {
List<String> nodes = new ArrayList<String>();
nodes.add("localhost:5701");
ClientConfig clientConfig = new ClientConfig();
ClientNetworkConfig networkConfig = new ClientNetworkConfig();
networkConfig.setAddresses(nodes);
clientConfig.setNetworkConfig(networkConfig);
SerializationConfig serCong = clientConfig.getSerializationConfig();
serCong.addPortableFactory(1, new UserFactoryImpl());
serCong.setPortableVersion(1);
HazelcastInstance hzClient1 = HazelcastClient.newHazelcastClient(clientConfig);
IMap<String, User> map = hzClient1.getMap("user");
System.out.println(map.size() + "hiten");
User user1 = new User();
user1.setFirstName("hiten");
user1.setLastName("singh");
map.put("1", user1);
//hz1.getLifecycleService().terminate();
System.out.println(map.size() + "after");
User user2 = new User();
user2.setFirstName("hiten1");
user2.setLastName("singh1");
map.put("2", user2);
UserEntryProcessor entryProc = new UserEntryProcessor();
User userRes = (User)map.executeOnKey("1", entryProc);
}
static class UserEntryProcessor implements EntryProcessor<String, User>, HazelcastInstanceAware {
private transient HazelcastInstance hazelcastInstance;
#Override
public Object process(Entry<String, User> entry) {
User user = entry.getValue();
if(user != null) {
System.out.println(user.getFirstName());
}
return user;
}
#Override
public EntryBackupProcessor<String, User> getBackupProcessor() {
return null;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
}
static class UserFactoryImpl implements PortableFactory{
public final static int USER_PORTABLE_ID = 1;
public final static int FACTORY_ID = 1;
public Portable create(int classId) {
switch (classId) {
case USER_PORTABLE_ID:
return new User();
}
return null;
}
}
static class User implements Portable {
private String firstName;
private String lastName;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Override
public int getFactoryId() {
return UserFactoryImpl.FACTORY_ID;
}
#Override
public int getClassId() {
return UserFactoryImpl.USER_PORTABLE_ID;
}
#Override
public void writePortable(PortableWriter writer) throws IOException {
writer.writeUTF("first_name", firstName);
writer.writeUTF("last_name", lastName);
}
#Override
public void readPortable(PortableReader reader) throws IOException {
firstName = reader.readUTF("first_name");
lastName = reader.readUTF("last_name");
}
}
}
Yes it does, just as you figured out the factory and the classes need to be available. Currently there is no built-in solution to not share classes for more sophisticated use cases than simple gets / puts. I have JSON support and some other ideas cooking but nothing really done yet.
My code like this:
Java:
#Autowired
private RedisTemplate<String,User> myTemplate;
#Override
public String login(String email, String password) {
User user = this.userRepository.findByEmailAndPassword(email, password);
System.out.println(user);
if (user == null) return null;
String key1 = "lic" + "$" + user.getId() + "$" + user.getRole() + "$" + user.getName() + "$" + user.getEmail();
ValueOperations<String, User> ops = this.myTemplate.opsForValue();
if (!this.myTemplate.hasKey(key1)) {
ops.set(key1, user);
}
return key1;
}
when app run, inject bean ,like this:
#SpringBootApplication
public class ApplicationApp extends WebMvcConfigurerAdapter {
// #Autowired
// private RedisTemplate<String,String> template;
#Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
#Bean
RedisTemplate<String, User> redisTemplate() {
final RedisTemplate<String, User> template = new RedisTemplate<String, User>();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericToStringSerializer<User>(User.class));
template.setValueSerializer(new GenericToStringSerializer<User>(User.class));
return template;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
// super.addInterceptors(registry);
registry.addInterceptor(new AuthorAccess()).addPathPatterns("/api/sc/**");
}
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationApp.class, args);
}
}
then , call login service found error like this:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type com.qycloud.oatos.license.domain.User to type java.lang.String
Set ValueSerializer with Jackson2JsonRedisSerializer instead of GenericToStringSerializer and it should work. GenericToStringSerializer do not support Object to String conversion.
template.setValueSerializer(new Jackson2JsonRedisSerializer<User>(User.class));
You need to register you're own implementation of TypeConverter or a ConversionService able to deal with User.class via eg. setTypeConverter(TypeConverter converter). Otherwise GenericToStringSerializer will just try using the DefaultConversionService which does not know about your type.
I have a wcfservice where it gets request and sends a response.
In the request object one of my element is of type DateTime.
When i am passing correct format of DateTime(eg:2012-12-30),the response object works fine and there are no issues.
But when i pass the element in correct format(eg: 201-12-30),the service gives exception and throws invalid date format exception.
Correct request:
<req:paymentDateDate>2012-12-12</req:paymentDateDate>
Bad request
<req:paymentDateDate>2012-12-12</req:paymentDateDate>
and the response will be
<InnerException i:nil="true"/>
<Message>String was not recognized as a valid DateTime.</Message>
how to validate it from code,I am validating for mindate as following:
else if (request.paymentRequest.payment.paymentDateDate == DateTime.MinValue )
{
FaultException fx = BillPayFaultResponse(request, "Schema Validation Failed", "Invalid content,element 'paymentDateDate' is required,but not found.");
throw fx;
}
how to validate for whether my service is receiving valid datetime string or not
If you just need to check your date for being in some date range, it is better for you to implement IParameterInspector. It will allow you to check parameters both on client and service sides.
Here is an example of DateTime Validation:
IParameterInspector & IOperationBehavior implementations:
public class DateTimeParameterInspector: IParameterInspector
{
private static readonly ILog Logger = LogManager.GetLogger(typeof (DateTimeParameterInspector));
private static readonly DateTime MinDateTime = new DateTime(1900, 1, 1);
private static readonly DateTime MaxDateTime = new DateTime(2100, 1, 1);
private readonly int[] _paramIndecies;
public DateTimeParameterInspector(params int[] paramIndex)
{
_paramIndecies = paramIndex;
}
public object BeforeCall(string operationName, object[] inputs)
{
try
{
foreach (var paramIndex in _paramIndecies)
{
if (inputs.Length > paramIndex)
{
var dt = (DateTime) inputs[paramIndex];
if (dt < MinDateTime || dt > MaxDateTime)
{
var errorMessage = String.Format(
"Invalid date format. Operation name: {0}, param index{1}", operationName, paramIndex);
Logger.Error(errorMessage);
throw new FaultException(errorMessage);
}
}
}
}
catch(InvalidCastException exception)
{
Logger.Error("Invalid parameter type", exception);
throw new FaultException(
"Invalid parameter type");
}
return null;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{ }
}
public class DateTimeInspectorAttrubute: Attribute, IOperationBehavior
{
private readonly int[] _paramIndecies;
public DateTimeInspectorAttrubute(params int[] indecies)
{
_paramIndecies = indecies;
}
public void Validate(OperationDescription operationDescription)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(new DateTimeParameterInspector(_paramIndecies));
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
clientOperation.ParameterInspectors.Add(new DateTimeParameterInspector(_paramIndecies));
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
}
Here is an example of our parameter inspector usage:
[ServiceContract]
public interface IPricingService
{
[OperationContract]
[DateTimeInspectorAttrubute(0, 1)]
string GetPrice(DateTime startDate, DateTime endDate);
}
public class PricingService : IPricingService
{
public string GetPrice(DateTime startDate, DateTime endDate)
{
return "result";
}
}
In case you can have you your soap message invalide date, and you want to check it, you have to refer to IDispatchMessageInspector
To make the code to be compliled you have to reference System.ServiceModel, log4net (you can find it in nuget repository)