ConcurrentModifcationException happens occasionally - java

I have a function with a line that is supposedly meant to prevent a concurrent modification exception
List parseObjectKeys = new ArrayList<>(parseObject.keySet());
However it still happens every now and again
private static void convertParseObject(ParseObject parseObject,
HashMap<String, HashMap<String, WritableMap>> topLevel,
ArrayList<Task<Void>> tasks) {
if (parseObject != null) {
String className = parseObject.getClassName();
String id = parseObject.getObjectId();
if (!topLevel.containsKey(className)) {
topLevel.put(className, new HashMap<String, WritableMap>());
}
if (!topLevel.get(className).containsKey(id)) {
final WritableMap flatMap = Arguments.createMap();
flatMap.putString("class", className);
flatMap.putString("id", id);
if (parseObject.isDataAvailable()) {
topLevel.get(className).put(id, flatMap);
// This is required to prevent a ConcurrentModificationException
List<String> parseObjectKeys = new ArrayList<>(parseObject.keySet());
for (final String key : parseObjectKeys) {
Object value = parseObject.get(key);
if (value instanceof String) {
flatMap.putString(key, (String) value);
} else if (value instanceof Boolean) {
flatMap.putBoolean(key, (Boolean) value);
} else if (value instanceof Integer) {
flatMap.putInt(key, (Integer) value);
} else if (value instanceof Double) {
flatMap.putDouble(key, (Double) value);
} else if (value instanceof Date) {
flatMap.putString(key, Utils.toISO8601UTC((Date)value));
}
else {
if (value != null &&
!(value instanceof ParseACL)) {
Log.e(TAG, "Unknown type: " + value.getClass());
}
}
}
}
}
}

HashMap is not a thread-safe data structure, so you can use ConcurrentHashMap instead of HashMap.
use ConcurrentHashMap<String, ConcurrentHashMap<String, WritableMap>> topLevel
instead of
HashMap<String, HashMap<String, WritableMap>> topLevel.
and put List<String> parseObjectKeys = new ArrayList<>(parseObject.keySet());
in synchronized block.
Hope it will help.

Solution!!!
Add synchronized block like this
private synchronized void convertParseObject() { }

Related

Error when convert element type object to map entry

i have problem when i want to convert from object to map.entry. when i want try there is any problem here.and i have try to fix it there is no suggestion here. why like that ?
here my source code
private static HashMap getCommonEnvironment(final List blacklist) {
final String[] entries = { "PATH", "PATH", "LD_LIBRARY_PATH", "LD_ASSUME_KERNEL", "USER", "TMP", "TEMP", "HOME", "HOMEPATH", "LANG", "TZ", "OS" };
final HashMap defaultEnv = new HashMap();
Method m = null;
try {
m = System.class.getMethod("getenv", String.class);
}
catch (Exception ex) {}
for (int i = 0; i < entries.length; ++i) {
String val = null;
if (m != null) {
try {
val = (String)m.invoke(System.class, entries[i]);
}
catch (Exception e2) {
m = null;
}
}
if (val == null) {
try {
val = System.getProperty(entries[i]);
}
catch (Exception ex2) {}
}
if (val != null && !blacklist.contains(entries[i])) {
defaultEnv.put(entries[i], val);
}
}
String key;
String val = key = null;
if (new File("c:/winnt").isDirectory()) {
val = "c:\\winnt";
}
else if (new File("c:/windows").isDirectory()) {
val = "c:\\windows";
}
try {
final String s = System.getenv(key = "SystemRoot");
if (s != null) {
val = s;
}
}
catch (Throwable t) {}
try {
final String s = System.getProperty(key = "Windows.SystemRoot");
if (s != null) {
val = s;
}
}
catch (Throwable t2) {}
if (val != null && !blacklist.contains(key)) {
defaultEnv.put("SystemRoot", val);
}
try {
m = System.class.getMethod("getenv", (Class<?>[])Util.ZERO_PARAM);
final Map map = (Map)m.invoke(System.class, Util.ZERO_ARG);
for (final Map.Entry entry : map.entrySet()) {
key = (String) entry.getKey();
val = (String) entry.getValue();
if (!blacklist.contains(key)) {
defaultEnv.put(key, val);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return defaultEnv;
}
my error is in line my ide said cannot convert from object to map.entry
for (final Map.Entry entry : map.entrySet()) {
key = (String) entry.getKey();
val = (String) entry.getValue();
if (!blacklist.contains(key)) {
defaultEnv.put(key, val);
}
my question is what wrong with this code ?
I guess this map obtained by reflection is just a subclass of java map,only served iterators.(reference Array.asList()).
Maybe you can try this code:
for(Object obj : map.entrySet())
{
key = (String)obj.getKey();
value = (String)obj.getValue();
}
final Map<String,String> map = m.invoke(System.class, Util.ZERO_ARG);
for (final Map.Entry<String,String> entry : map.entrySet()) {
key = entry.getKey();
val = entry.getValue();
if (!blacklist.contains(key)) {
defaultEnv.put(key, val);
}
}
you can add the concrete type.

Removing memory leak issue

I'm working on a maintenance project and a issue is raised for memory leak.
Basically the code is to load the values of data in application context from database. If the values in DB is changed then this functionality is used to update the value in application context also without restarting the server.
The variables annotated with #Value annotation are updated every where in the project, eg:
#Value("${cost}")
private String cost;
The method where memory leak is reported by production is updateObjects():
public class DbPropertySourcesPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private CustomBeanPostProcessor customBeanPostProcessor;
private static Properties dbProps = new Properties();
private void updateObjects() {
for (String key : customBeanPostProcessor.getObjectMap().keySet()) {
if (null != dbProps.get(key)) {
List<Object> objectList = customBeanPostProcessor.getObjectMap().get(key);
if (objectList != null && objectList.size() > 0) {
for (Object object : objectList) {
if (null != object) {
for (Field field : object.getClass().getDeclaredFields()) {
Value value = field.getAnnotation(Value.class);
if (null != value && null != value.value()
&& value.value().replace("${", "").replace("}", "").length() > 0
&& value.value().replace("${", "").replace("}", "").equalsIgnoreCase(key)
&& field.getType() == String.class) {
field.setAccessible(true);
try {
field.set(object, dbProps.get(key));
}
catch (IllegalAccessException ee) {
logger.error("Unable to update Object",ee);
}
}
}
}
}
}
}
}
}
Is it because of reflection used & can reflectionUtils of spring solve the problem?
CustomBeanPostProcessor.java
public class CustomBeanPostProcessor implements BeanPostProcessor {
public static Map<String, ArrayList<Object>> objectMap;
public Object postProcessBeforeInitialization(Object o, String string) throws BeansException {
return(o);
}
public Object postProcessAfterInitialization(Object o, String string) throws BeansException {
if(objectMap == null) {
objectMap = new HashMap<String, ArrayList<Object>>();
}
if(null == o) {
return(o);
}
if(AopUtils.isAopProxy(o) && o instanceof Advised) {
Class targetClass = ((Advised)o).getTargetClass();
Object object = null;
try {
Object target = ((Advised)o).getTargetSource().getTarget();
object = targetClass.cast(target);
for(Field field:object.getClass().getDeclaredFields()) {
Value value = field.getAnnotation(Value.class);
if(null != value && null != value.value() && value.value().replace("${", "").replace("}", "").length() > 0) {
updateObjectMap(value.value().replace("${", "").replace("}", ""), object);
}
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
else {
for(Field field:o.getClass().getDeclaredFields()) {
Value value = field.getAnnotation(Value.class);
if(null != value && null != value.value() && value.value().replace("${", "").replace("}", "").length() > 0) {
updateObjectMap(value.value().replace("${", "").replace("}", ""), o);
}
}
}
return(o);
}
public static void updateObjectMap(String key, Object object) {
ArrayList<Object> objectList = objectMap.get(key);
if(null == objectList) {
objectList = new ArrayList<Object>();
objectList.add(object);
objectMap.put(key, objectList);
}
else {
objectList.add(object);
}
}
public Map<String, ArrayList<Object>> getObjectMap() {
return objectMap;
}
public void setObjectMap(Map<String, ArrayList<Object>> objectMap) {
this.objectMap = objectMap;
}
}
Please let me know if more information is required.
Thank You.

MsgPack Serialize a JsonObject in Android

I have a JsonObject that contains several JsonArrays:
{
"key1" : [[1, 2, 3, 4]],
"key2" : [[1, 2, 3, 4]]
}
I would like to pack it using MessagePack without using the JsonObjects string representation,
So far i haven't found any documentation as to how to accomplish this,
Any ideas?
I have written a recursive code in order to achieve this,
Here is the code if anyone else has encountered this issue:
public byte[] convert(JSONObject data) throws IOException, JSONException {
MessageBufferPacker packer = MessagePack.newDefaultBufferPacker();
packJObject(packer, data);
packer.close();
return packer.toByteArray();
}
private void packJObject(MessageBufferPacker packer, JSONObject data) throws IOException, JSONException {
packer.packMapHeader(data.length());
Iterator<String> keys = data.keys();
while(keys.hasNext()) {
String key = keys.next();
packer.packString(key); // pack the key
Object value = data.get(key);
if(value instanceof JSONArray) {
packJArray(packer, (JSONArray)value);
}
else if(value instanceof JSONObject) {
packJObject(packer, (JSONObject) value);
}
else {
packPrimitive(packer, value);
}
}
}
private void packJArray(MessageBufferPacker packer, JSONArray data) throws IOException, JSONException {
packer.packArrayHeader(data.length());
for(int i = 0; i < data.length(); i++) {
Object value = data.get(i);
if(value instanceof JSONObject) {
packJObject(packer,(JSONObject)value);
}
else if(value instanceof JSONArray){
packJArray(packer,(JSONArray)value);
}
else {
packPrimitive(packer, value);
}
}
}
private void packPrimitive(MessageBufferPacker packer, Object value) throws IOException {
if(value instanceof String) {
packer.packString((String)value);
}
else if(value instanceof Integer) {
packer.packInt((Integer) value);
}
else if(value instanceof Boolean) {
packer.packBoolean((boolean)value);
}
else if(value instanceof Double) {
packer.packDouble((double)value);
}
else if(value instanceof Long) {
packer.packLong((long)value);
}
else {
throw new IOException("Invalid packing value of type " + value.getClass().getName());
}
}

Convert a Bundle to JSON

I'd like to convert the an Intent's extras Bundle into a JSONObject so that I can pass it to/from JavaScript.
Is there a quick or best way to do this conversion? It would be alright if not all possible Bundles will work.
You can use Bundle#keySet() to get a list of keys that a Bundle contains. You can then iterate through those keys and add each key-value pair into a JSONObject:
JSONObject json = new JSONObject();
Set<String> keys = bundle.keySet();
for (String key : keys) {
try {
// json.put(key, bundle.get(key)); see edit below
json.put(key, JSONObject.wrap(bundle.get(key)));
} catch(JSONException e) {
//Handle exception here
}
}
Note that JSONObject#put will require you to catch a JSONException.
Edit:
It was pointed out that the previous code didn't handle Collection and Map types very well. If you're using API 19 or higher, there's a JSONObject#wrap method that will help if that's important to you. From the docs:
Wrap an object, if necessary. If the object is null, return the NULL
object. If it is an array or collection, wrap it in a JSONArray. If it
is a map, wrap it in a JSONObject. If it is a standard property
(Double, String, et al) then it is already wrapped. Otherwise, if it
comes from one of the java packages, turn it into a string. And if it
doesn't, try to wrap it in a JSONObject. If the wrapping fails, then
null is returned.
private String getJson(final Bundle bundle) {
if (bundle == null) return null;
JSONObject jsonObject = new JSONObject();
for (String key : bundle.keySet()) {
Object obj = bundle.get(key);
try {
jsonObject.put(key, wrap(bundle.get(key)));
} catch (JSONException e) {
e.printStackTrace();
}
}
return jsonObject.toString();
}
public static Object wrap(Object o) {
if (o == null) {
return JSONObject.NULL;
}
if (o instanceof JSONArray || o instanceof JSONObject) {
return o;
}
if (o.equals(JSONObject.NULL)) {
return o;
}
try {
if (o instanceof Collection) {
return new JSONArray((Collection) o);
} else if (o.getClass().isArray()) {
return toJSONArray(o);
}
if (o instanceof Map) {
return new JSONObject((Map) o);
}
if (o instanceof Boolean ||
o instanceof Byte ||
o instanceof Character ||
o instanceof Double ||
o instanceof Float ||
o instanceof Integer ||
o instanceof Long ||
o instanceof Short ||
o instanceof String) {
return o;
}
if (o.getClass().getPackage().getName().startsWith("java.")) {
return o.toString();
}
} catch (Exception ignored) {
}
return null;
}
public static JSONArray toJSONArray(Object array) throws JSONException {
JSONArray result = new JSONArray();
if (!array.getClass().isArray()) {
throw new JSONException("Not a primitive array: " + array.getClass());
}
final int length = Array.getLength(array);
for (int i = 0; i < length; ++i) {
result.put(wrap(Array.get(array, i)));
}
return result;
}
Here is a Gson type adapter factory that converts a Bundle to JSON.
https://github.com/google-gson/typeadapters/blob/master/android/src/main/java/BundleTypeAdapterFactory.java
If the bundle has nested bundles then JSONObject.wrap(bundle.get(key)) will return null. So I managed to get it to work for my use case with this recursive function. Haven't tested more advanced use cases though.
JSONObject json = convertBundleToJson(bundle);
public JSONObject convertBundleToJson(Bundle bundle) {
JSONObject json = new JSONObject();
Set<String> keys = bundle.keySet();
for (String key : keys) {
try {
if (bundle.get(key) != null && bundle.get(key).getClass().getName().equals("android.os.Bundle")) {
Bundle nestedBundle = (Bundle) bundle.get(key);
json.put(key, convertToJson(nestedBundle));
} else {
json.put(key, JSONObject.wrap(bundle.get(key)));
}
} catch(JSONException e) {
System.out.println(e.toString());
}
}
return json;
}
Object myJsonObj = bundleObject.get("yourKey");
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(myJsonObj.toString()).getAsJsonObject();
json.get("memberInJson").getAsString();
private static void createFlatJSon(Bundle appRestrictions, JSONObject jsonObject) throws JSONException{
for (String key : appRestrictions.keySet()) {
if (appRestrictions.get(key) instanceof Bundle) {
Bundle bundle = (Bundle)appRestrictions.get(key);
Map<String, String> map = ((Bundle)appRestrictions.get(key)).keySet().stream().collect(Collectors.toMap(x -> x, x -> bundle.get(x).toString()));
JSONObject jsonNested = new JSONObject(map);
jsonObject.put(key,jsonNested);
//createFlatJSon((Bundle) appRestrictions.get(key),jsonObject);
}else if (appRestrictions.get(key) instanceof Parcelable[]){
for (int i=0;i< ((Parcelable[]) appRestrictions.get(key)).length; i++){
createFlatJSon((Bundle)((Parcelable[]) appRestrictions.get(key))[i],jsonObject);
}
//Log.e("KEY skipped",appRestrictions.get(key).toString());
}else{
// map = appRestrictions.keySet().stream().collect(Collectors.toMap(x -> x, x -> appRestrictions.get(x).toString()));// Use this if don't want to modify the keys
Log.e("KEY: ", key + " Value:" + appRestrictions.getString(key));
Log.e("KEY: ", key + " Value:" + appRestrictions.get(key).getClass().getSimpleName());
if (appRestrictions.get(key) instanceof String[]){
JSONArray jsonArray = new JSONArray();
for (String value : (String[])appRestrictions.get(key)) {
jsonArray.put(value);
}
jsonObject.put(key,jsonArray);
}else {
jsonObject.put(key, appRestrictions.get(key).toString());
}
}
}
}

which is best way to map servlet request parameters to a java class? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Easy way of populating Javabeans based on request parameters
Hi,
I have a Java Object with a set of search parameters, sth. like
public class SearchRequest {
private String customerName;
private String city;
...
}
This request has to be filled by a servet request.
But instead of writing code like
...
SearchRequest searchRequest = new SearchRequest();
if (request.getParameter("customerName") != null)
{
searchRequest.setCustomerName(request.getParameter("customerName"));
}
if (request.getParameter("city") != null)
{
searchRequest.setCity(request.getParameter("city"));
}
...
I'm looking for a more generic way.
I was checking the mapping tool Dozer but did not find a nice way how to handle this mapping.
Now I think reflection would be a choice.
Is this true?
If so does anyone has a code sniplet how this can be done with reflection?
I plead guilty:
public void save(HttpServletRequest req, Object obj) {
Set<String> names = new HashSet<String>();
#SuppressWarnings("unchecked")
Enumeration<String> enm = req.getParameterNames();
while (enm.hasMoreElements()) {
names.add(enm.nextElement());
}
Class clazz = obj.getClass();
while (clazz != Object.class && !names.isEmpty()) {
for (Field f: clazz.getDeclaredFields()) {
if (!Modifier.isTransient(f.getModifiers())) {
String name = f.getName();
if (names.contains(name)) {
try {
names.remove(name);
f.setAccessible(true);
Object val = convertValue(req, f.getType(),
name);
f.set(obj, val);
} catch (ParseException ex) {
LOG.error("Error assigning field", ex);
} catch (IllegalAccessException ex) {
LOG.error("Error assigning field", ex);
}
}
}
}
clazz = clazz.getSuperclass();
}
}
private Object convertValue(HttpServletRequest req, Class<?> type,
String name) throws ParseException {
if (type.isArray()) {
Class<?> elemType = type.getComponentType();
String strings[] = req.getParameterValues(name);
if (strings == null || strings.length == 0) {
return new Object[0];
}
Object array = Array.newInstance(elemType, strings.length);
for (int i = 0; i < strings.length; ++i) {
Object val = parse(elemType, strings[i]);
Array.set(array, i, val);
}
return array;
} else {
String s = req.getParameter(name);
if (s == null) {
return null;
}
return parse(type, s);
}
}
public static Object parse(Class<?> type, String value)
throws ParseException {
if (type == String.class) {
return value;
} else if (value == null || value.length() == 0) {
return null;
} else if (Enum.class.isAssignableFrom(type)) {
#SuppressWarnings("unchecked")
Object result = Enum.valueOf((Class<? extends Enum>)type, value);
return result;
} else if (type == boolean.class || type == Boolean.class) {
return "true".equals(value);
} else if (type == byte.class || type == Byte.class) {
return Byte.valueOf(value);
} else if (type == short.class || type == Short.class) {
return Short.valueOf(value);
} else if (type == int.class || type == Integer.class) {
return Integer.valueOf(value);
} else if (type == long.class || type == Long.class) {
return Long.valueOf(value);
} else if (type == float.class || type == Float.class) {
return Float.valueOf(value);
} else if (type == double.class || type == Double.class) {
return Double.valueOf(value);
} else if (type == Date.class) {
return new SimpleDateFormat("dd/MM/yyyy").parse(value);
} else if (type == BigDecimal.class) {
DecimalFormat format = getDecimalFormat("0.00");
return format.parse(value);
} else {
throw new RuntimeException("Cannot convert value of type " + type);
}
}
private static DecimalFormat getDecimalFormat(String pattern) {
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat(pattern);
format.setParseBigDecimal(true);
format.setDecimalFormatSymbols(symbols);
return format;
}

Categories

Resources