Java associate data with current thread - java

I am working on web application, which is deployed on apache tomcat web server. I want to associate data with current thread of http request. For this purpose I have created following class:
public class ThreadData {
private static final Map<Long, Map<String, String>> data = new HashMap<>();
public static Map<String, String> getDataMap(long threadId) {
if (data.get(threadId) == null) {
data.put(threadId, new HashMap<String, String>());
}
return data.get(threadId);
}
public static void put(String key, String value) {
long threadId = Thread.currentThread().getId();
getDataMap(threadId).put(key, value);
}
public static String get(String key) {
long threadId = Thread.currentThread().getId();
return getDataMap(threadId).get(key);
}
}
I want to know if such kind of solution is right and safe for this problem .

What you are trying to achieve is covered by ThreadLocal class, in your case it would be
ThreadLocal<Map<String, String>> data = new ThreadLocal<Map<String, String>>() {
#Override
protected Map<String, String> initialValue() {
return new HashMap<>();
}
};
If you still want to use put or get, you may define them in such a way:
public static void put(String key, String value) {
data.get().put(key, value);
}
public static String get(String key) {
return data.get().get(key);
}

Related

How can I mock a private final field?

I have the class below:
Class Test{
private final Map<String, Map<BigInteger, String>> holder = new ConcurrentHashMap<>();
public boolean checkIfExists(String key){
return holder.containsKey(key);
}
}
I want to write test case for checkIfExists, How do I mock holder i.e Map in this scenario.
Better way for doing that, is creating a constructor having as an argument the holder attribute, then, you can mock it, or use an stub.
Class Test{
private final Map<String, Map<BigInteger, String>> holder;
public Test(final Map<String, Map<BigInteger, String>> holder){
this.holder = holder;
}
public boolean checkIfExists(String key){
return holder.containsKey(key);
}
}

Store object for later use in java

I'm working on API testing automation using Rest assured. I would like to store Response as an object after calling an API so I can validate some data using that object like, status code, body, header and all.
I tried using System.setPropery but it allows to store only String and if store Response as String like System.setProperty("test", response.toString()); and try to retrieve System.getProperty("test"); then throws the error
java.lang.ClassCastException: java.lang.String cannot be cast to
io.restassured.response.Response
It there a way to store an object somewhere and access it for later use?
Don't use System.Properties for this purpose.
Please use a simple cache store as given below.
public class ResponseCache {
private static final ResponseCache myInstance = new ResponseCache();
private final Map<String, Response> cacheStore = new HashMap<>();
private ResponseCache() {
}
public static ResponseCache getInstance() {
return myInstance;
}
public void addResponse(String key, Response value) {
cacheStore.put(key, value);
}
public boolean exists(String key) {
return cacheStore.containsKey(key);
}
public void remove(String key) {
if (exists(key)) {
cacheStore.remove(key);
}
}
public Response get(String key) {
return exists(key) ? cacheStore.get(key) : null;
}
}
Once your execution work is completed you can remove that key.

REST GET Response with Object containing a HashMap

I have following Rest service which queries a database, constructs multiple "Chat"-objects and returns them as an array:
#GET
#Path("/getChats")
#Produces(MediaType.APPLICATION_JSON)
public Chat[] getChats(#QueryParam("userId") String userId){
ArrayList<Chat> chats = getChatsDB(userId);
Chat[] chatAr = new Chat[chats.size()];
return chats.toArray(chatAr);
}
The "Chat"-class is a POJO:
import java.util.HashMap;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#JsonIgnoreProperties(ignoreUnknown = true)
public class Chat {
private String userId1;
private String userId2;
private HashMap<String, String> msgs;
public Chat() {
msgs = new HashMap<>();
}
public String getUserId1() {
return userId1;
}
public void setUserId1(String userId1) {
this.userId1 = userId1;
}
public String getUserId2() {
return userId2;
}
public void setUserId2(String userId2) {
this.userId2 = userId2;
}
public void addMsg(String date, String msg){
msgs.put(date, msg);
}
public HashMap<String, String> getMsgs() {
return msgs;
}
}
The client code for getting this chat objects is :
public static Chat[] getChats() {
Chat[] chats = null;
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
String chatUrl = url+"getChats?userId="+user.getId();
chats = restTemplate.getForObject(chatUrl, Chat[].class);
for(Chat c: chats){
System.out.println(c.getUserId1());
System.out.println(c.getUserId2());
for(Map.Entry<String,String> e : c.getMsgs().entrySet()){
System.out.println(e.getKey() + e.getValue());
}
}
return chats;
The client recieves the chat objects, but without the HashMap with the messages. c.getUserId1 and c.getUserId2 return the correct values, but the HashMap is empty. This problem is only on the client side. The chat-objects in the servicemethod getChats(#QueryParam("userId") String userId) have the correct values in the HashMap.
Opening the link in the browser shows this:
[{"userId1":"414","userId2":"12"}]
You need to have both getter and setter in your POJO for the inner map.
public class Chat {
private HashMap<String, String> msgs;
public void setMsgs(HashMap<String, String> msgs) {
this.msgs = msgs;
}
// rest of the code ...
}
If you don't want to change pojo implementation for some reason, you can setup Jackson to use private fields and not getters/setters, something like this: how to specify jackson to only use fields - preferably globally
For some reason your serverside sends you
"maps":{"entry":[{"key":"key1","value":"value1"}]}
instead of
"maps":{"key1":"value1","key2":"value2"}
You can probably solve it with just client side pojo changes like this:
public void setMsgs(Map<String, List<Map<String,String>>> entries){
for (Map<String, String> entry: entries.get("entry"))
msgs.put(entry.get("key"),entry.get("value"));
}

How do use ConcurrencyHashmap another class or main method?

public class keyClientHandler extends ChannelInboundHandlerAdapter{
public static ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
String information;
String hashMapKey;
String hashMapValue;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// do something
keyTable.put(hashMapKey, hashMapValue);
System.out.println(keyTable.size()); //size = 268
}
public static ConcurrentHashMap<String,String> getKeyTable() {
return keyTable;
}
Another class use:
public static void main(String[] args) {
ConcurrentHashMap<String, String> map = keyClientHandler.getKeyTable();
System.out.println(map.size()); //size=0
}
When i try to use stuffed concurrentMap on another class or in the main method, it returns empty.
How can i use Concurentmap from another classes?
How we interpreted your problem?
public static ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
static concurrentHashMap has been defined in class KeyClientHandler. You intended to retrieve the map object and print the size of the map from main method of another class. Now as you said, your program runs and it prints 0 as the output. This means you are alright in terms of accessing the map. You should have got compilation errors, if your concurrentHashMap was not accessible from the said main method of another class.
What can be a possible way to demonstrate that this better?
I think the following improvements are required. Firstly, you don't need to use static map or static methods here. We can demonstrate this without static'ness as well. Try running this example which is a slight modification of your code.
import java.util.concurrent.ConcurrentHashMap;
class ChannelHandlerContext {
// some class
}
class KeyClientHandler{
public ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
String information;
String hashMapKey;
String hashMapValue;
KeyClientHandler() {
}
public void setKeyValue(String key, String value){
hashMapKey = key;
hashMapValue = value;
}
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// do something
keyTable.put(hashMapKey, hashMapValue);
System.out.println(keyTable.size()); //size = 268
}
public ConcurrentHashMap<String,String> getKeyTable() {
return keyTable;
}
}
public class TestConcurrentHashMap {
public static void main(String[] args) {
KeyClientHandler keyClientHandler = new KeyClientHandler();
keyClientHandler.setKeyValue("apples", "fruit");
ConcurrentHashMap<String, String> map = keyClientHandler.getKeyTable();
try {
keyClientHandler.channelRead(null, null); // not the best thing
System.out.println(map.size()); //size=1
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output:
1
My project is socket programming. I use Netty Framework. I send TCP client and received message send other client.
Server :
public class KeyClient {
static final String HOST = System.getProperty("host", "...");
static final int PORT = Integer.parseInt(System.getProperty("port", "..."));
public static void keyClientStart() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new keyClientInitializer());
ChannelFuture future = bootstrap.connect(HOST, PORT).sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
KeyClientInitializer :
public class keyClientInitializer extends ChannelInitializer<SocketChannel> {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LoggingHandler(LogLevel.INFO));
pipeline.addLast(new FixedLengthFrameDecoder(32));
pipeline.addLast(new keyClientHandler());
}
}
KeyClientHandler :
public class keyClientHandler extends ChannelInboundHandlerAdapter{
public static ConcurrentHashMap<String, String> keyTable = new ConcurrentHashMap<>();
String information;
String hashMapKey;
String hashMapValue;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buffer = (ByteBuf) msg;
byte[] receivedKey = byteBufToByteArray(buffer);
information = DatatypeConverter.printHexBinary(receivedKey);
// do something
// ...
keyTable.put(hashMapKey, hashMapValue); //map has elements
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
public static ConcurrentHashMap<String,String> getKeyTable() {
return keyTable;
}
private byte[] byteBufToByteArray(ByteBuf buffer) {
byte[] receivedKey;
int offset;
int length = buffer.readableBytes();
if (buffer.hasArray()) {
receivedKey = buffer.array();
offset = buffer.arrayOffset();
} else {
receivedKey = new byte[length];
buffer.getBytes(buffer.readerIndex(), receivedKey);
offset = 0;
}
return receivedKey;
}
}
Test class:
public class AppMain {
public static void main(String[] args) throws InterruptedException {
KeyClient.keyClientStart();
ConcurrentHashMap<String, String> map = keyClientHandler.getKeyTable(); // is empty
}
When i add 'System.out.println(keyTable);' in keyClientHandler, i see map values.
Output
On my case it's OK to hold the CHM object on other class, you can check:
Is the System.out.println(keyTable.size()); called after channelRead(...) ? you print the key on which class? if the next channel handler, should you call ctx.fireChannelRead(msg); ?
Other way you can print the CHM hashCode(), if they are the same, that means same object.

Mock private static method in final class using PowerMockito

I have a final class with private static method which is invoked inside another static method
public final class GenerateResponse{
private static Map<String, String> getErrorDetails(JSONObject jsonObject) {
// implementation
}
public static String method1(params...){
Map<String, String> map = getErrorDetails(new JsonObject());
// implementation
}
}
I need to mock the private static method call getErrorDetails(), but my test is calling the actual method. Here is my code:
#RunWith(PowerMockRunner.class)
#PrepareForTest(GenerateResponse.class)
public class GenerateResponseTest{
#Test
public void testFrameQtcErrorResponse() throws Exception {
Map<String, String> errorDtls = new HashMap<String, String>();
PowerMockito.spy(GenerateResponse.class);
PowerMockito.doReturn(errorDtls).when(GenerateResponse.class, "getErrorDetails", JSONObject.class);
String response = GenerateResponse.method1(params...);
}
You should use an argument matcher in the whenmethod. I've modified your code a little bit to run the test case.
Actual method
public final class GenerateResponse{
private static Map<String, String> getErrorDetails(JSONObject jsonObject) {
return null;
}
public static String method1() {
Map<String, String> map = getErrorDetails(new JSONObject());
return map.get("abc");
}
}
Test method
#RunWith(PowerMockRunner.class)
#PrepareForTest(GenerateResponse.class)
public class GenerateResponseTest {
#Test
public void testFrameQtcErrorResponse() throws Exception {
Map<String, String> errorDtls = new HashMap<String, String>();
errorDtls.put("abc", "alphabets");
PowerMockito.mockStatic(GenerateResponse.class, Mockito.CALLS_REAL_METHODS);
PowerMockito.doReturn(errorDtls).when(GenerateResponse.class,
"getErrorDetails", Matchers.any(JSONObject.class));
String response = GenerateResponse.method1();
System.out.println("response =" + response);
}
}
Output
response =alphabets

Categories