I have 2 classes and contains the below property languageMap
class Person {
Map<String, String> languageMap;
}
class Employee {
Map<String, String> languageMap;
}
There are two methods addressMap(List<Person> persons) and employeeMap(List<Employee> employee) it calls Function interface,
public Map<String, String addressMap(List<Person> persons){
Function<Collection<Person>,
Map<String, String>> personFunc = CommonUtils::buildPersonMap;
return personFunc.apply(persons);
}
public Map<String, String employeeMap(List<Employee> employee){
Function<Collection<Employee>,
Map<String, String>> addressFunc = CommonUtils::buildEmployeeMap;
return addressFunc.apply(employee);
}
private static Map<String, String> buildPersonMap(Collection<Person> personItem) {
return personItem.stream()
.filter(element -> element.getLanguageMap() != null)
.flatMap(element -> element.getLanguageMap()
.entrySet()
.stream())
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
private static Map<String, String> buildEmployeeMap(Collection<Employee> employeeItem) {
return employeeItem.stream()
.filter(element -> element.getLanguageMap() != null)
.flatMap(element -> element.getLanguageMap()
.entrySet()
.stream())
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
I wanted to make the 2 buildXXX() methods to be common, and tried to use Generics as below,
private static Map<String, String> buildMap(Collection<?> input) {
return input.stream()
.filter(element -> element.getLanguageMap() != null). // ERROR
.flatMap(element -> element.getLanguageMap().entrySet().stream()) // ERROR
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
any Generics or Stream technique to overcome the issue?
You can make the caller send in a getter for each type, and have your method implemented in this way:
private static <T> Map<String, String> buildMap(Collection<T> input,
Function<T, Map<String, String>> languageMapGetter) {
return input.stream()
.map(languageMapGetter) //you can also call it yourself
.filter(Objects::nonNull)
.flatMap(element -> element.entrySet().stream())
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue, (a, b) -> a));
}
Which will make your type-specific methods look like this:
public Map<String, String> addressMap(List<Person> persons) {
return CommonUtils.buildMap(persons, Person::getLanguageMap);
}
public Map<String, String> employeeMap(List<Employee> employee) {
return CommonUtils.buildMap(employee, Employee::getLanguageMap);
}
Related
I recently upgraded my app to .net core 6 and now I am getting this error when trying to get a service using this code:
IUnityContainer container = HangfireUnityConfig.GetConfiguredContainer();
var authService = container.Resolve<IAuthService>();
I read some other posts that mentioned adding HttpContextAccessor in my ConfigureServices() method but none of the ways ive tried fixed the error.
services.AddHttpContextAccessor();
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Another person mentioned adding the line in my Program.cs but still getting the error.
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
If I add RegisterType<IHttpContextAccessor, HttpContextAccessor>() to RegisterTypes() in my HangFireUnityConfig class the error goes away but throws a new error later on so Im not sure if thats the right fix.
public static void RegisterTypes(IUnityContainer container)
{
// register hangfire dependencies
container.RegisterType<IHttpContextAccessor, HttpContextAccessor>()
}
AuthService.cs
using MyApp.Entities.DTOs;
namespace MyApp.Service.Auth
{
public class AuthService : IAuthService
{
private UserDto currentUser = null;
private readonly IHttpContextAccessor _context;
public AuthService(IHttpContextAccessor ctx)
{
_context = ctx;
currentUser = parseClaimsUser();
}
public bool isInRole(string role, List<string> roleList)
{
return true;
}
public UserDto parseClaimsUser()
{
ClaimsPrincipal currentClaim = _context.HttpContext.User;
UserDto parsedUser = new UserDto();
bool isAdmin = false;
if (currentClaim == null || !currentClaim.Identity.IsAuthenticated)
{
return parsedUser;
}
//return user id from token properties
parsedUser.userID = currentClaim.Claims.Where(claim => claim.Type == ClaimTypes.NameIdentifier).Select(v => v.Value).FirstOrDefault<string>();
// retrieve groups from token properties --- this is only retrieved upon login. Users will have to log out and log back in to see any changes in groups
var currentGroupsIDs = currentClaim.HasClaim(claim => claim.Type == ClaimTypes.Role) ?
currentClaim.Claims.Where(t => t.Type == ClaimTypes.Role).Select(y => int.Parse(y.Value)).ToList<int>()
: new List<int>();
var adminString = currentClaim.Claims.Where(claim => claim.Type == ClaimTypes.AuthorizationDecision)
.Select(v => v.Value)
.SingleOrDefault<string>();
adminString = adminString == null ? "False" : adminString;
isAdmin = bool.Parse(adminString);
//parsedUser.userGrp = currentGroups;
parsedUser.userGrpIDs = currentGroupsIDs;
parsedUser.isAuthenticated = currentClaim.Identity.IsAuthenticated;
parsedUser.displayName = currentClaim.Identity.Name;
parsedUser.email = currentClaim.Claims.Where(w => w.Type == ClaimTypes.Email).Select(v => v.Value).SingleOrDefault<string>();
//parsedUser.currentToken = tokenExtract;
parsedUser.isAdmin = isAdmin;
var isUS = currentClaim.Claims.Where(claim => claim.Type == "us_citizen").Select(v => v.Value).SingleOrDefault<string>();
if (isUS != null)
{
parsedUser.isUSCitizenAndJPLEmployee = bool.Parse(isUS);
}
return parsedUser;
}
public void initUser()
{
currentUser = parseClaimsUser();
}
public UserDto getCurrentUser(bool includeToken = false)
{
if (currentUser == null || currentUser.userID == null)
{
currentUser = parseClaimsUser();
}
if (!includeToken)
{
currentUser.currentToken = null;
}
return currentUser;
}
public bool userIsAdmin()
{
return true;
}
}
}
I was able to figure out the error I was getting with my last implementation. The error was with not being able to cast my dbContext to type IObjectContextAdapter.
public List<KeyValuePair<string, long>> GetKeys(EntityEntry entry)
{
var keys = new List<KeyValuePair<string, long>>();
var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
if (objectStateEntry.EntityKey.EntityKeyValues != null)
{
keys.AddRange(objectStateEntry.EntityKey.EntityKeyValues.Select(key => new KeyValuePair<string, long>(key.Key, Convert.ToInt64(key.Value))));
}
return keys;
}
I refactored the code to look like this and got no errors.
public List<KeyValuePair<string, long>> GetKeys(EntityEntry entry)
{
//this gets an array of the key names
var keyNames = entry.Metadata.FindPrimaryKey()
.Properties
.Select(p => p.Name)
.ToArray();
var keys = new List<KeyValuePair<string, long>>();
if (keyNames != null)
{
//creates the KeyValuePairs
keys.AddRange(keyNames.Select(key => new KeyValuePair<string, long>(key, Convert.ToInt64(entry.Property(key).CurrentValue))));
}
return keys;
}
The messages are getting consumed from kafka topic using json deserializer(spring commons). The generic messages structure as below.
GenericEvent:
{
"id": "10000",
"payload": {
"id": 100
"attribute1": "hi",
"attribute2": "hello"
},
"type": {
"id" : 1,
"name" : "A"
}
}
Different types has different payload and the structure of the payload also will be varied. So i would like to process the payload based on the type.
My respective POJO is as below, and total 3 different payloads and respective payload pojos has been created.
GenericEvent {
private int id;
private T payload:
private Type type;
}
Right now i am using the below code to convert
JsonNode jsonNode = objectMapper.readTree("messagefromKafka);
GenericEvent genericEvent = objectMapper.convertValue(jsonNode, new TypeReference<GenericEvent>() {});
But the code is throwing java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class GenericEvent .
Can someone help on this issue?
EDIT:
//Generic Object i have provided already
//Payload Object - applicable for different types - A, B, C, D
public class Payload {
private int id;
private String name;
private String address;
private String typeAAttribute1; //applicable for type A attribute
private String typeAAttribute2; //applicable for type A attribute
private String typeBAtribute1; //applicable for type B attribute
private String typeABAtribute2; //applicable for type A,B attibute
private String typeCtribute1; //applicable for type C attibute
private String typeABCAtribute1;//applicable for type A,B,C attibute
}
Kafka consumer config:
---------------------
import org.springframework.kafka.support.serializer.JsonDeserializer;
#Bean
public ConcurrentKafkaListenerContainerFactory<Object, Object> reprocessListenerContainerFactory() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
props.put(ConsumerConfig.ALLOW_AUTO_CREATE_TOPICS_CONFIG, false);
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapservers);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, latest);
props.put(ConsumerConfig.GROUP_ID_CONFIG, "testgroupid");
props.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, "300000");
ConcurrentKafkaListenerContainerFactory<Object, Object> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(new DefaultKafkaConsumerFactory<>(props));
factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
factory.setRecordFilterStrategy(
(consumerRecord) -> {
try {
JsonNode jsonNode = objectMapper.readTree(consumerRecord.value().toString());
GenericEvent genericEvent = objectMapper.convertValue(jsonNode, new TypeReference<GenericEvent>() {});
log.info(
"Retrieved the record {} from the partition {} with offset {}",
consumerRecord.value(),
consumerRecord.partition(),
consumerRecord.offset());
//Process type A and B events
if (genericEvent.getType().equalIgnoreCase("A") || genericEvent.getType().equalIgnoreCase("B"))) {
return false;
}
return true;
} catch (Exception ex) {
log.error("Error occured:{}", ex.getStackTrace());
return true;
}
});
return factory;
}
//Listener
#KafkaListener(id = "MYREPROCESS-ID", topics = "reprocess-test",
containerFactory = "reprocessListenerContainerFactory",
autoStartup = "true")
public void onMessage(ConsumerRecord<String, String> consumerRecord, Acknowledgment acknowledgment) {
JsonNode jsonNode = objectMapper.readTree("messagefromKafka);
GenericEvent genericEvent = objectMapper.convertValue(jsonNode, new TypeReference<GenericEvent>() {});
//I should identify the respective payload during runtime
Payload payload = genericEvent.getPayload();
if (genericEvent.getType().equalsIgnoreCase("A") {
processPayload(payload);
} else {
processPayload(payload);
}
}
Something is odd. Since you are using the Spring JsonDeserializer, you have to tell it what to convert to; properties are documented here https://docs.spring.io/spring-kafka/docs/current/reference/html/#serdes-json-config).
In that case, you would get ConsumerRecord<?, GenericEvent>.
If you want to receive ConsumerRecord<String, String> and do the conversion yourself, you should use StringDeserializer s instead.
I am trying to read custom annotation value loaded through a different classloader.
How do I convert the Annotation object to json?
#Retention(RententionPolicy.RUNTIME)
public #interface SendEmail{
public String id;
}
Gson gson = new Gson();
Object object = (Object)annotation // this holds SendEmail object loaded from different classloader
gson.toJson(object);
//I get UnsupportedOperationException: Attempted to Serialize java.lang.Class: SendEmail. Forget to register a type adapter?
What is the type adapter to be used for interfaces?
I'm not really sure why you need to serialize annotation instances that are constant by design, but you're most likely using an Oracle JVM that instantiates annotations using java.lang.proxy.Proxy. Proxies are treated as reflective-access data objects in Gson (and there are no mentions of proxies in the standard Gson bundle) and Gson just fails on serializing java.lang.Class which does not make much sense in your scenario.
You need to create a new type adapter factory that can emit an annotation-aware type adapter that would use reflection over annotations heavily. Say,
final class AnnotationTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory instance = new AnnotationTypeAdapterFactory();
private AnnotationTypeAdapterFactory() {
}
static TypeAdapterFactory getInstance() {
return instance;
}
#Override
#Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
#Nullable
final Class<? extends Annotation> annotationClass = Annotations.lookupAnnotationClass(typeToken.getRawType());
if ( annotationClass == null ) {
return null;
}
final List<Method> methods = Annotations.lookupMethods(annotationClass);
final int count = methods.size();
final String[] names = new String[count];
#SuppressWarnings("unchecked")
final TypeAdapter<Object>[] typeAdapters = new TypeAdapter[count];
final Map<String, TypeAdapter<Object>> namedTypeAdapters = new HashMap<>();
for ( int i = 0; i < count; i++ ) {
final Method method = methods.get(i);
names[i] = method.getName();
#SuppressWarnings({ "unchecked", "rawtypes" })
final TypeAdapter<Object> typeAdapter = (TypeAdapter) gson.getAdapter(method.getReturnType());
typeAdapters[i] = typeAdapter;
namedTypeAdapters.put(names[i], typeAdapter);
}
final TypeAdapter<T> typeAdapter = new TypeAdapter<T>() {
#Override
#SuppressWarnings("resource")
public void write(final JsonWriter out, final T annotation)
throws IOException {
try {
out.beginObject();
for ( int i = 0; i < count; i++ ) {
out.name(names[i]);
typeAdapters[i].write(out, methods.get(i).invoke(annotation));
}
out.endObject();
} catch ( final IllegalAccessException | InvocationTargetException ex ) {
throw new RuntimeException(ex);
}
}
#Override
public T read(final JsonReader in)
throws IOException {
try {
in.beginObject();
final Map<String, Object> properties = new HashMap<>();
while ( in.hasNext() ) {
final String name = in.nextName();
#Nullable
final TypeAdapter<Object> objectTypeAdapter = namedTypeAdapters.get(name);
if ( objectTypeAdapter == null ) {
in.skipValue();
} else {
properties.put(name, objectTypeAdapter.read(in));
}
}
in.endObject();
#SuppressWarnings("unchecked")
final T annotation = (T) Annotations.create(annotationClass, properties);
return annotation;
} catch ( final NoSuchMethodException ex ) {
throw new RuntimeException(ex);
}
}
};
return typeAdapter.nullSafe();
}
}
where the Annotations class is as follows:
final class Annotations {
private static final boolean SUN_PACKAGE = false;
private Annotations() {
}
static <T extends Annotation> T create(final Class<T> annotationClass, final Map<String, Object> properties)
throws NoSuchMethodException {
return create(annotationClass.getClassLoader(), annotationClass, properties);
}
static <T extends Annotation> T create(final ClassLoader classLoader, final Class<T> annotationClass, final Map<String, Object> properties)
throws NoSuchMethodException {
if ( SUN_PACKAGE ) {
#SuppressWarnings("unchecked")
final T annotation = (T) AnnotationParser.annotationForMap(annotationClass, properties);
return annotation;
}
#SuppressWarnings("unchecked")
final T annotation = (T) Proxy.newProxyInstance(
classLoader,
new Class<?>[]{ annotationClass },
DynamicAnnotation.fromMap(annotationClass, lookupProperties(annotationClass, properties))
);
return annotation;
}
#Nullable
static Class<? extends Annotation> lookupAnnotationClass(final Class<?> clazz) {
if ( clazz.isAnnotation() ) {
#SuppressWarnings("unchecked")
final Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) clazz;
return annotationClass;
}
final Class<?>[] interfaces = clazz.getInterfaces();
if ( interfaces.length != 1 ) {
return null;
}
final Class<?> iface = interfaces[0];
if ( !Annotation.class.isAssignableFrom(iface) ) {
return null;
}
#SuppressWarnings("unchecked")
final Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) iface;
return annotationClass;
}
static List<Method> lookupMethods(final Class<? extends Annotation> annotationClass) {
final List<Method> methods = new ArrayList<>();
for ( final Method method : annotationClass.getMethods() ) {
if ( method.getDeclaringClass() == annotationClass ) {
methods.add(method);
}
}
return Collections.unmodifiableList(methods);
}
static Map<String, Object> lookupProperties(final Class<? extends Annotation> annotationClass, final Map<String, Object> properties) {
final Map<String, Object> namedProperties = new HashMap<>();
namedProperties.putAll(lookupDefaultProperties(annotationClass));
namedProperties.putAll(properties);
return Collections.unmodifiableMap(namedProperties);
}
static Map<String, Object> lookupDefaultProperties(final Class<? extends Annotation> annotationClass) {
final Map<String, Object> defaultProperties = new HashMap<>();
for ( final Method method : lookupMethods(annotationClass) ) {
#Nullable
final Object defaultValue = method.getDefaultValue();
if ( defaultValue != null ) {
defaultProperties.put(method.getName(), defaultValue);
}
}
return Collections.unmodifiableMap(defaultProperties);
}
static String toString(#SuppressWarnings("TypeMayBeWeakened") final Class<? extends Annotation> annotationClass, final Map<String, Object> properties) {
final StringBuilder builder = new StringBuilder("#")
.append(annotationClass.getTypeName())
.append('(');
boolean atTail = false;
for ( final Map.Entry<String, Object> e : properties.entrySet() ) {
if ( atTail ) {
builder.append(", ");
}
builder.append(e.getKey())
.append('=')
.append(e.getValue());
atTail = true;
}
return builder.append(')')
.toString();
}
}
and a custom implementation of annotations:
abstract class DynamicAnnotation
implements Annotation, InvocationHandler {
private static final Method java_lang_Object_equals;
private static final Method java_lang_Object_hashCode;
private static final Method java_lang_Object_toString;
private static final Method java_lang_annotation_Annotation_annotationType;
static {
try {
java_lang_Object_equals = Object.class.getDeclaredMethod("equals", Object.class);
java_lang_Object_hashCode = Object.class.getDeclaredMethod("hashCode");
java_lang_Object_toString = Object.class.getDeclaredMethod("toString");
java_lang_annotation_Annotation_annotationType = Annotation.class.getDeclaredMethod("annotationType");
} catch ( final NoSuchMethodException ex ) {
throw new Error(ex);
}
}
private final String toString;
private final Class<? extends Annotation> annotationClass;
private DynamicAnnotation(final String toString, final Class<? extends Annotation> annotationClass) {
this.toString = toString;
this.annotationClass = annotationClass;
}
static DynamicAnnotation fromMap(final Class<? extends Annotation> annotationClass, final Map<String, Object> properties)
throws NoSuchMethodException {
return FromMap.create(annotationClass, properties);
}
#Nullable
protected abstract Object invoke(final Method method)
throws Throwable;
#Override
public final Class<? extends Annotation> annotationType() {
return annotationClass;
}
// must conform the https://docs.oracle.com/javase/6/docs/api/java/lang/annotation/Annotation.html#hashCode() contract
#Override
public final int hashCode() {
//return hashCode;
throw new UnsupportedOperationException();
}
// must conform the https://docs.oracle.com/javase/6/docs/api/java/lang/annotation/Annotation.html#equals(java.lang.Object) contract
#Override
public final boolean equals(#Nullable final Object obj) {
throw new UnsupportedOperationException();
}
#Override
public final String toString() {
return toString;
}
#Override
#Nonnull
public final Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
if ( method.equals(java_lang_annotation_Annotation_annotationType) ) {
return annotationType();
}
if ( method.equals(java_lang_Object_equals) ) {
return equals(args[0]);
}
if ( method.equals(java_lang_Object_hashCode) ) {
return hashCode();
}
if ( method.equals(java_lang_Object_toString) ) {
return toString();
}
#Nullable
final Object returnValue = invoke(method);
if ( returnValue == null ) {
throw new NoSuchMethodException("The instance of " + annotationClass + " has no value associated with " + method.getName());
}
return returnValue;
}
private static final class FromMap
extends DynamicAnnotation {
private final Map<String, Object> properties;
private FromMap(final String toString, final Class<? extends Annotation> annotationClass, final Map<String, Object> properties) {
super(/*hashCode, */toString, annotationClass);
this.properties = properties;
}
private static DynamicAnnotation create(final Class<? extends Annotation> annotationClass, final Map<String, Object> properties)
throws NoSuchMethodException {
final Map<String, Object> toStringProperties = new LinkedHashMap<>();
for ( final Method method : Annotations.lookupMethods(annotationClass) ) {
final String name = method.getName();
if ( !properties.containsKey(name) ) {
throw new NoSuchMethodException("Cannot find " + name + " in " + properties + " while constructing an instance of " + annotationClass);
}
final Object value = properties.get(name);
toStringProperties.put(name, value);
}
final String toString = Annotations.toString(annotationClass, Collections.unmodifiableMap(toStringProperties));
return new FromMap(toString, annotationClass, properties);
}
#Override
protected Object invoke(final Method method) {
return properties.get(method.getName());
}
}
}
You might also use AnnotationUtils (if it works for you), or AnnotationParser from the "sun package" (if it's an option either) to fulfill the annotation interface contracts.
Here is an example of use for round-trip:
private static final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(AnnotationTypeAdapterFactory.getInstance())
.create();
public static void main(final String... args)
throws NoSuchFieldException {
final SendEmail before = Wrapper.class.getDeclaredField("constant").getAnnotation(SendEmail.class);
System.out.println(before);
final String json = gson.toJson(before);
System.out.println(json);
final SendEmail after = gson.fromJson(json, SendEmail.class);
System.out.println(after);
System.out.println(after.annotationType());
System.out.println(gson.toJson(after));
}
private static final class Wrapper {
#SendEmail(id = "email#mail.com")
private static final Object constant = new Object();
}
I am trying to merge several Map into a single map, for doing this I wrote this piece of code.
public static Map<String, Long> mergeMaps(List<Map<String, Long>> maps){
Map<String, Long> mergedMap = new TreeMap<>();
maps.forEach( map -> {
//Map<String, Long> mx = new TreeMap<>(map);
map.forEach((key, value) -> mergedMap.merge(key, value, Long::sum));
});
logger.info("Merge map successful");
return mergedMap;
}
On doing this the code is throwing an error :
org.springframework.batch.core.step.AbstractStep java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[?:1.8.0_201-1-ojdkbuild]
lambda$mergeMaps$1
I have this pojo
public class MappingDto {
public MappingDto(){
map1 = new LinkedHashMap<>();
map2 = new LinkedHashMap<>();
map3 = new LinkedHashMap<>();
}
private Map<String, Long> map1;
private Map<String, Long> map2;
private Map<String, Long> map3;
getters()/Setters()
toString()
}
I populate this pojo maps with the below codes.
MappingDto.setMap1(Arrays.asList(doc.getDescription().split("\\s+")).stream().collect(Collectors.groupingBy(Function.identity(),LinkedHashMap::new,Collectors.counting())));
after generating this I have to merge this map with the some Stored in File, To read the Map I have the below method.
public static <T> T readJsonFile(String filePath, T t) throws JAXBException, IOException, IllegalAccessException, InstantiationException {
ObjectMapper mapper = new ObjectMapper();
if(!Utils.checkIfFileExists(filePath)){
Utils.createANewFile(filePath);
return t;
}
return mapper.readValue(new File(filePath), new TypeReference<T>(){});
}
After getting this maps I pass it to the
mergeMaps(Arrays.asList(MappingDto.getMap1(),storedData));
and
List<Map<String, Long>> dataList = new LinkedList<>();
dataList.add(MappingDto.getMap1());
dataList.add(MappingDto.getMap2());
dataList.add(MappingDto.getMap3());
mergeMaps(dataList);
I went through this code several time, But not able to figure what exactly is causing this issue.
One is reading the Stored JSON map
public static <T> T readJsonFile(String filePath, Class<T> t) throws JAXBException, IOException, IllegalAccessException, InstantiationException {
ObjectMapper mapper = new ObjectMapper();
if(!Utils.checkIfFileExists(filePath)){
Utils.createANewFile(filePath);
return t.newInstance();
}
return mapper.readValue(new File(filePath), new TypeReference<T>(){});
}
I tried this and several other variations but no results.
public static Map<String, Long> mergeMaps(List<Map<String, Long>> maps){
Map<String, Long> mergedMap = new TreeMap<>();
maps.forEach( map -> {
//Map<String, Long> mx = new TreeMap<>(map);
map.forEach((key, value) -> mergedMap.merge(key, Long.valueOf(value), Long::sum));
});
logger.info("Merge map successful");
return mergedMap;
}
Can you please help me understand what is in Integer and why is being cast to Long
Thanks in advance.
I got the following function
Map<MyClass, String> someFunction() {
Map<MyClass, String> result = new HashMap<>();
return result.put(new MyClass("someString"), "someOtherString"));
}
The implementation of MyClass looks like the following:
public class MyClass{
String string;
public MyClass(String string) {
this.string = string;
}
public void setString(String string) {
this.string = string;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((string== null) ? 0 : string.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
MyClass other = (MyClass) obj;
if (string== null) {
if (other.string!= null) {
return false;
}
} else if (!string.equals(other.string)) {
return false;
}
return true;
}
}
In my test I am doing the following:
#Test
public void test() {
Map<MyClass, String> outcome = classUnderTest.someFunction();
assertThat(outcome.get(new MyClass("someString")), is("someOtherString"));
}
But this test fails, because actual is null.
If I try the following:
assertThat(outcome.keySet(), hasItem(MY_CLASS));
this also fails, telling me, that these are different intantiations. I even tried to debug my test, but it never reaches the equals method. Can you tell me what is happening here?
Are you sure, that your method doesn't modify the objecT? I think, that someFunction replaces the string in MyClass. That causes that your object of MyClass return another hashCode.
A HashMap works like that:
put:
compute hashCode of the key. Store value under that hashCode
get:
compute hashCode of the key. Search for a value with that hashCode. If there is a value, then maybe call equals.
So: never use mutable values as key! Otherwise, you may lose your data (or make it difficult to resolve)
Just try to execute this test, it should be green
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
public class SomeTest {
Map<MyClass, String> someFunction() {
Map<MyClass, String> result = new HashMap<>();
result.put(new MyClass("someString"), "someOtherString");
return result;
}
#Test
public void test() {
Map<MyClass, String> outcome = someFunction();
assertThat(outcome.get(new MyClass("someString")), is("someOtherString"));
}
public static class MyClass {
String string;
public MyClass(String string) {
this.string = string;
}
public void setString(String string) {
this.string = string;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((string == null) ? 0 : string.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
MyClass other = (MyClass) obj;
if (string == null) {
if (other.string != null) {
return false;
}
} else if (!string.equals(other.string)) {
return false;
}
return true;
}
}
}
but if you modify MyClass object after it was added to Map, the test became red:
Map<MyClass, String> someFunction() {
Map<MyClass, String> result = new HashMap<>();
MyClass key = new MyClass("someOldString");
result.put(key, "someOtherString");
key.setString("someString");
return result;
}
In your function you are returning null
From the JavaDoc for HashMap:
public V put(K key, V value)
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
Specified by:
put in interface Map<K,V>
Overrides:
put in class AbstractMap<K,V>
Parameters:
key - key with which the specified value is to be associated
value - value to be associated with the specified key
Returns:
the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)
put() returns what used to be there, not what you just put there