diff --git a/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java b/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java
index 7700e6d295..e2f14eafdb 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java
@@ -22,11 +22,13 @@ package com.zabbix.gateway;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.HashSet;
+import javax.management.AttributeList;
 
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanServerConnection;
 import javax.management.ObjectName;
+import javax.management.MalformedObjectNameException;
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.TabularDataSupport;
 import javax.management.remote.JMXConnector;
@@ -47,6 +49,7 @@ class JMXItemChecker extends ItemChecker
 
 	private String username;
 	private String password;
+	private String jmx_endpoint;
 
 	static final int DISCOVERY_MODE_ATTRIBUTES = 0;
 	static final int DISCOVERY_MODE_BEANS = 1;
@@ -55,8 +58,6 @@ class JMXItemChecker extends ItemChecker
 	{
 		super(request);
 
-		String jmx_endpoint;
-
 		try
 		{
 			jmx_endpoint = request.getString(JSON_TAG_JMX_ENDPOINT);
@@ -192,8 +193,16 @@ class JMXItemChecker extends ItemChecker
 			if (2 < argumentCount)
 				throw new ZabbixException("required key format: jmx.discovery[<discovery mode>,<object name>]");
 
-			JSONArray counters = new JSONArray();
-			ObjectName filter = (2 == argumentCount) ? new ObjectName(item.getArgument(2)) : null;
+			ObjectName filter;
+
+			try
+			{
+				filter = (2 == argumentCount) ? new ObjectName(item.getArgument(2)) : null;
+			}
+			catch (MalformedObjectNameException e)
+			{
+				throw new ZabbixException("invalid object name format: " + item.getArgument(2));
+			}
 
 			int mode = DISCOVERY_MODE_ATTRIBUTES;
 			if (0 != argumentCount)
@@ -206,6 +215,8 @@ class JMXItemChecker extends ItemChecker
 					throw new ZabbixException("invalid discovery mode: " + modeName);
 			}
 
+			JSONArray counters = new JSONArray();
+
 			for (ObjectName name : mbsc.queryNames(filter, null))
 			{
 				logger.trace("discovered object '{}'", name);
@@ -276,13 +287,60 @@ class JMXItemChecker extends ItemChecker
 
 	private void discoverAttributes(JSONArray counters, ObjectName name) throws Exception
 	{
-		for (MBeanAttributeInfo attrInfo : mbsc.getMBeanInfo(name).getAttributes())
+		Map<String, Object> values = new HashMap<String, Object>();
+		MBeanAttributeInfo[] attributeArray = mbsc.getMBeanInfo(name).getAttributes();
+
+		if (0 == attributeArray.length)
+		{
+			logger.trace("object has no attributes");
+			return;
+		}
+
+		String[] attributeNames = getAttributeNames(attributeArray);
+		AttributeList attributes;
+		String discoveredObjKey = jmx_endpoint + "#" + name;
+		Long expirationTime = JavaGateway.iterativeObjects.get(discoveredObjKey);
+		long now = System.currentTimeMillis();
+
+		if (null != expirationTime && now <= expirationTime)
+		{
+			attributes = getAttributesIterative(name, attributeNames);
+		}
+		else
+		{
+			try
+			{
+				attributes = getAttributesBulk(name, attributeNames);
+
+				if (null != expirationTime)
+					JavaGateway.iterativeObjects.remove(discoveredObjKey);
+			}
+			catch (Exception e)
+			{
+				attributes = getAttributesIterative(name, attributeNames);
+
+				// This object's attributes will be collected iteratively for next 24h. After that it will
+				// be checked if it is possible to successfully collect all attributes in bulk mode.
+				JavaGateway.iterativeObjects.put(discoveredObjKey, now + SocketProcessor.MILLISECONDS_IN_HOUR * 24);
+			}
+		}
+
+		if (attributes.isEmpty())
+		{
+			logger.warn("cannot process any attribute for object '{}'", name);
+			return;
+		}
+
+		for (javax.management.Attribute attribute : attributes.asList())
+			values.put(attribute.getName(), attribute.getValue());
+
+		for (MBeanAttributeInfo attrInfo : attributeArray)
 		{
 			logger.trace("discovered attribute '{}'", attrInfo.getName());
 
-			if (!attrInfo.isReadable())
+			if (null == values.get(attrInfo.getName()))
 			{
-				logger.trace("attribute not readable, skipping");
+				logger.trace("cannot retrieve attribute value, skipping");
 				continue;
 			}
 
@@ -290,7 +348,7 @@ class JMXItemChecker extends ItemChecker
 			{
 				logger.trace("looking for attributes of primitive types");
 				String descr = (attrInfo.getName().equals(attrInfo.getDescription()) ? null : attrInfo.getDescription());
-				findPrimitiveAttributes(counters, name, descr, attrInfo.getName(), mbsc.getAttribute(name, attrInfo.getName()));
+				findPrimitiveAttributes(counters, name, descr, attrInfo.getName(), values.get(attrInfo.getName()));
 			}
 			catch (Exception e)
 			{
@@ -301,6 +359,52 @@ class JMXItemChecker extends ItemChecker
 		}
 	}
 
+	private String[] getAttributeNames(MBeanAttributeInfo[] attributeArray)
+	{
+		int i = 0;
+		String[] attributeNames = new String[attributeArray.length];
+
+		for (MBeanAttributeInfo attrInfo : attributeArray)
+		{
+			if (!attrInfo.isReadable())
+			{
+				logger.trace("attribute '{}' not readable, skipping", attrInfo.getName());
+				continue;
+			}
+
+			attributeNames[i++] = attrInfo.getName();
+		}
+
+		return attributeNames;
+	}
+
+	private AttributeList getAttributesBulk(ObjectName name, String[] attributeNames) throws Exception
+	{
+		return mbsc.getAttributes(name, attributeNames);
+	}
+
+	private AttributeList getAttributesIterative(ObjectName name, String[] attributeNames)
+	{
+		AttributeList attributes = new AttributeList();
+
+		for (String attributeName: attributeNames)
+		{
+			try
+			{
+				Object attrValue = mbsc.getAttribute(name, attributeName);
+				attributes.add(new javax.management.Attribute(attributeName, attrValue));
+			}
+			catch (Exception e)
+			{
+				Object[] logInfo = {name, attributeName, ZabbixException.getRootCauseMessage(e)};
+				logger.warn("attribute processing '{},{}' failed: {}", logInfo);
+				logger.debug("error caused by", e);
+			}
+		}
+
+		return attributes;
+	}
+
 	private void discoverBeans(JSONArray counters, ObjectName name)
 	{
 		try
diff --git a/src/zabbix_java/src/com/zabbix/gateway/JavaGateway.java b/src/zabbix_java/src/com/zabbix/gateway/JavaGateway.java
index d2bda29268..a32a76a8a5 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/JavaGateway.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/JavaGateway.java
@@ -22,6 +22,9 @@ package com.zabbix.gateway;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.util.concurrent.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -29,6 +32,7 @@ import org.slf4j.LoggerFactory;
 public class JavaGateway
 {
 	private static final Logger logger = LoggerFactory.getLogger(JavaGateway.class);
+	public static final Map<String, Long> iterativeObjects = Collections.synchronizedMap(new HashMap<>());
 
 	public static void main(String[] args)
 	{
diff --git a/src/zabbix_java/src/com/zabbix/gateway/SocketProcessor.java b/src/zabbix_java/src/com/zabbix/gateway/SocketProcessor.java
index 7f769aae7b..0ab0c65144 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/SocketProcessor.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/SocketProcessor.java
@@ -20,6 +20,8 @@
 package com.zabbix.gateway;
 
 import java.net.Socket;
+import java.util.Map;
+import java.util.Iterator;
 
 import org.json.*;
 
@@ -30,8 +32,11 @@ class SocketProcessor implements Runnable
 {
 	private static final Logger logger = LoggerFactory.getLogger(SocketProcessor.class);
 
+	private static long cleanupTime = System.currentTimeMillis();
 	private Socket socket;
 
+	public static final long MILLISECONDS_IN_HOUR = 1000 * 60 * 60;
+
 	SocketProcessor(Socket socket)
 	{
 		this.socket = socket;
@@ -52,9 +57,21 @@ class SocketProcessor implements Runnable
 			JSONObject request = new JSONObject(speaker.getRequest());
 
 			if (request.getString(ItemChecker.JSON_TAG_REQUEST).equals(ItemChecker.JSON_REQUEST_INTERNAL))
+			{
 				checker = new InternalItemChecker(request);
+			}
 			else if (request.getString(ItemChecker.JSON_TAG_REQUEST).equals(ItemChecker.JSON_REQUEST_JMX))
+			{
 				checker = new JMXItemChecker(request);
+
+				long now = System.currentTimeMillis();
+
+				if (now >= cleanupTime)
+				{
+					cleanDiscoveredObjects(now);
+					cleanupTime = now + MILLISECONDS_IN_HOUR;
+				}
+			}
 			else
 				throw new ZabbixException("bad request tag value: '%s'", request.getString(ItemChecker.JSON_TAG_REQUEST));
 
@@ -101,4 +118,17 @@ class SocketProcessor implements Runnable
 
 		logger.debug("finished processing incoming connection");
 	}
+
+	private void cleanDiscoveredObjects(long now)
+	{
+		for (Iterator<Map.Entry<String, Long>> it = JavaGateway.iterativeObjects.entrySet().iterator();
+			it.hasNext(); )
+		{
+			Map.Entry<String, Long> entry = it.next();
+			long expirationTime = entry.getValue();
+
+			if (now >= expirationTime)
+				it.remove();
+		}
+	}
 }
