Syntax highlighter header

Tuesday, 17 August 2021

Unable to make private java.lang.reflect.Proxy() accessible with JDK-17 in JUnit test using Ant

Recently I encountered the following error while executing Junit test case using Ant. My testcase uses EJBs from a wildfly 24 server. I am using jboss-client.jar file from same server in my testcase.

2021-08-17 16:39:30,450 2428  ERROR [com.tk20.ejb.api.util.EJBUtils] (main:[]) Unable to make private java.lang.reflect.Proxy() accessible: module java.base does not "opens java.lang.reflect" to unnamed module @
394df057
java.lang.reflect.InaccessibleObjectException: Unable to make private java.lang.reflect.Proxy() accessible: module java.base does not "opens java.lang.reflect" to unnamed module @394df057
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[?:?]
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[?:?]
        at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:188) ~[?:?]
        at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:181) ~[?:?]
        at org.jboss.marshalling.reflect.JDKSpecific$SerMethods.<init>(JDKSpecific.java:147) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.reflect.SerializableClass.<init>(SerializableClass.java:84) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.reflect.SerializableClassRegistry$1.computeValue(SerializableClassRegistry.java:62) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.reflect.SerializableClassRegistry$1.computeValue(SerializableClassRegistry.java:59) ~[jboss-client.jar:24.0.0.Final]
        at java.base/java.lang.ClassValue.getFromHashMap(ClassValue.java:228) ~[?:?]
        at java.base/java.lang.ClassValue.getFromBackup(ClassValue.java:210) ~[?:?]
        at java.base/java.lang.ClassValue.get(ClassValue.java:116) ~[?:?]
        at org.jboss.marshalling.reflect.SerializableClassRegistry.lookup(SerializableClassRegistry.java:83) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.reflect.SerializableClass.<init>(SerializableClass.java:76) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.reflect.SerializableClassRegistry$1.computeValue(SerializableClassRegistry.java:62) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.reflect.SerializableClassRegistry$1.computeValue(SerializableClassRegistry.java:59) ~[jboss-client.jar:24.0.0.Final]
        at java.base/java.lang.ClassValue.getFromHashMap(ClassValue.java:228) ~[?:?]
        at java.base/java.lang.ClassValue.getFromBackup(ClassValue.java:210) ~[?:?]
        at java.base/java.lang.ClassValue.get(ClassValue.java:116) ~[?:?]
        at org.jboss.marshalling.reflect.SerializableClassRegistry.lookup(SerializableClassRegistry.java:83) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1394) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:298) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:231) ~[jboss-client.jar:24.0.0.Final]
        at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.remote.RemoteClientTransport.lookup(RemoteClientTransport.java:271) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.remote.RemoteContext.lambda$lookupNative$0(RemoteContext.java:190) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.NamingProvider.performExceptionAction(NamingProvider.java:222) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.remote.RemoteContext.performWithRetry(RemoteContext.java:100) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.remote.RemoteContext.lookupNative(RemoteContext.java:188) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:74) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.store.RelativeFederatingContext.lookupNative(RelativeFederatingContext.java:58) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:74) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:60) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:66) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:66) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:66) ~[jboss-client.jar:24.0.0.Final]
        at org.wildfly.naming.client.WildFlyRootContext.lookup(WildFlyRootContext.java:144) ~[jboss-client.jar:24.0.0.Final]

The reason of failure was traced to version of Ant which I was using version 1.9.15 of Ant. After upgrading Ant to version 1.10.11 the error was removed. Due to some reason with older version of Ant JDKSpecific class which was being used was compatible with JDK8 and not the one which is compatible with JDK9 or higher. After upgrading Ant to 1.10.11 it started picking right version of class and problem was fixed.

Please refer to my earlier post regarding similar  error faced while accessing EJB in wildfly 24 without involvement of Ant and JUnit.  https://blog.bigdatawithjasvant.com/2021/07/javalangreflectinaccessibleobjectexcept.html

Friday, 13 August 2021

Implementing rate limit on an API

Here I am going to discuss an interesting programming problem. How to implement rate limit for an API per customer. You need to implement a rate limit of 10 requests per second with allowing a bust of 50 API calls. It means if user was silent for some time then tokens will accumulate up to 50 tokens and after that they will get expired. Every call will consume one token. One token will get accumulated every 100 milliseconds. 

Following is the implementation of code with limit of 10 API calls per second and allowing a bust of 50 API calls.


import java.util.HashMap;

public class RateLimitting {
	
	HashMap<String, Bucket> rateLimits = new HashMap<>();
	
	public static class Bucket {
		int tokens;
		long lastAccessTime;
		
		public Bucket() {
			tokens = 50;
			lastAccessTime = System.currentTimeMillis();
		}
	}
	
	public String api(String user, String req) {
		Bucket r = rateLimits.get(user);
		if(r==null) {
			r = new Bucket();
			rateLimits.put(user, r);
		} else {
			long current = System.currentTimeMillis();
			if((current - r.lastAccessTime)/100 >=1) {
				r.tokens = (int) (r.tokens + (current - r.lastAccessTime)/100);
				if(r.tokens>50) {
					r.tokens = 50;
				}
				r.lastAccessTime = current;
			}
		}
		
		if(r.tokens<0) {
			// deny the request
			return null;
		}
		
		r.tokens--;
		
		// Process the request
		return "Success";
		
	}
} 

Implement power function without using multiplication

In this post I am going to discuss one interesting  programming question. You are supposed to write power function without using multiply operator. You are allowed to use division operator but not multiply.

This is a good question to show your skill at optimizing code and showing that you don't miss the corner cases. You can use multiple additions to simulate multiplication. You need to make sure that you use lest number of additions. For example if you are multiplying 5 with 5 then you don't add 5 four time, you can do it by adding three times. You add 5 with 5 to get 10 in one addtion, You add 10 with 10 in second addition and after that you add 5 in third addition to get answer as 25.

You can implement one function for multiplying two numbers and use that function in your power function. Here again you need to make least number of calls to multiply function. For example if you are calculating 5^5 then we can do it with three calls to multiply functions instead of 4 calls. You multiply 5 with 5 in first call to get 25. You multiply 25 with 25 in second call and multiply 625 with 5 in third call.

Following is the java code for this question:


public class PowerWithoutMul {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		int m = 4;
		int n = 4;
		
		System.out.println(pow(m, n));
		

	}
	
	static int pow(int m, int n) {
		int res = 1;
		if(n/2>0) {
			int temp = pow(m, n/2);
			res = mul(temp, temp);
		}
		if(n%2==1) {
			res = mul(res, m);
		}
		return res;		
	}
	
	static int mul (int m, int k) {
		int res = 0;
		if(k/2>0) {
			int temp = mul(m, k/2);
			res =  temp + temp;
		}
		
		if(k%2 == 1) {
			res = res + m;
		}
		return res;
	}

}

Tuesday, 10 August 2021

Minimum number of swaps required to sort an array

I was reading one interesting post on GeeksForGeeks at https://www.geeksforgeeks.org/minimum-number-swaps-required-sort-array/

I found it very informative. I thought of explaining this problem in my words.

Problem statement:

Given an array of n distinct elements, find the minimum number of swaps required to sort the array.

Example:


Input: {4, 3, 2, 1}
Output: 2
Explanation: Swap index 0 with 3 and 1 with 2 to 
              form the sorted array {1, 2, 3, 4}.

Input: {1, 5, 4, 3, 2}
Output: 2

Solution to this problem lies in sorting this array and observing how many elements have changed their position. For the elements who has not changed their position no swap is needed. For the elements who have changed their positions there will be cycles like following image(from GeeksForGeeks.com)

In the above image there are two cycles of two elements each. To sort this array we need two swaps, one for each cycle. Now look at following image (from GeeksForGeeks.com) The above array contains two cycles one with 2 elements and one with 3 elements. We need one swap for correcting two element cycle and two swaps for correcting 3 element cycle. 
We need N-1 swaps for correcting a N element cycle. If we have a cycle a->b->c->d->e->a then this 5 element cycle can be corrected by 4 swaps:

  1. (a, b)
  2. (b, c) note b will be at a's original place
  3. (c, d) note c will be at a's original place
  4. (d, e) note d will be at a's original place

After 4th swap you notice e is at a's original place already so no swap is needed.

For counting number of swap we can calculate cycle size either forward or backward. If we have a cycle a->b->c->d->e->a .We can start at a's original place in sorted array and see that element e is present there, now we see which element it present at e's original place ,we find d there then we look at d's original place then we find c there. If we continue this way we find a at b's original place when we look for a's original place we find that it was already visited so we break out of the loop. This gives us size of the cycle. We mark all elements of this cycle visited so we don't get into this cycle one again.

Following is the code from GeeksForGeeks:

import java.util.*;
import java.io.*;

class GfG
{
	// Function returns the
	// minimum number of swaps
	// required to sort the array
	public static int minSwaps(int[] nums)
	{
		int len = nums.length;
		HashMap<Integer, Integer> map = new HashMap<>();
		for(int i=0;i<len;i++)
			map.put(nums[i], i);
			
		Arrays.sort(nums);
		
		// To keep track of visited elements. Initialize
		// all elements as not visited or false.
		boolean[] visited = new boolean[len];
		Arrays.fill(visited, false);
		
		// Initialize result
		int ans = 0;
		for(int i=0;i<len;i++) {
		
			// already swapped and corrected or
			// already present at correct pos
			if(visited[i] || map.get(nums[i]) == i)
				continue;
				
			int j = i, cycle_size = 0;
			while(!visited[j]) {
				visited[j] = true;
				
				// move to next node
				j = map.get(nums[j]);
				cycle_size++;
			}
			
			// Update answer by adding current cycle.
			if(cycle_size > 0) {
				ans += (cycle_size - 1);
			}
		}
		return ans;
	}
}

// Driver class
class MinSwaps
{
	// Driver program to test the above function
	public static void main(String[] args)
	{
		int []a = {1, 5, 4, 3, 2};
		GfG g = new GfG();
		System.out.println(g.minSwaps(a));
	}
}
// This code is contributed by Saurabh Johari

Monday, 9 August 2021

replacement of com.sun.jersey.spi.container.ContainerRequestFilters in jersey 2

Recently I was upgrading my application from Jersey 1 to Jersey 2. Following is my web.xml file in Jercey 1.


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" 
            xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>myapplication</display-name>
  <servlet>
    <servlet-name>jersey-serlvet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>myapplication</param-value>
    </init-param>
    <init-param>
	  <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
	  <param-value>common.SecurityFilter</param-value>
	</init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>jersey-serlvet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping> 
</web-app>

I found that in Jersey 2 replacement for com.sun.jersey.spi.container.servlet.ServletContainer is org.glassfish.jersey.servlet.ServletContainer . From documentation of org.glassfish.jersey.servlet.ServletContainer I found that replacement of com.sun.jersey.config.property.packages is  jersey.config.server.provider.packages . But I was unable to find replacement for init-param parameter com.sun.jersey.spi.container.ContainerRequestFilters .  It was big struggle to find a replacement for this.

After struggling for a long time I found that we don't need to put filter in web.xml file. It will be picked by package scanning. Following is my filter code. I changed package names according to jersey 2.


package common;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import java.util.Base64;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerRequestContext;

@Provider
public class SecurityFilter implements ContainerRequestFilter {

	private static final String X_API_KEY = "x-api-key";
	private static final String X_API_SECRET = "1234567890";
	
	@Override
	public void filter(ContainerRequestContext requestContext) {
		String authapikey = requestContext.getHeaderString(X_API_KEY);
		if(authapikey!=null && !authapikey.isEmpty()) {
			String decodedKey = new String(Base64.getDecoder().decode(authapikey)) ;
			if(X_API_SECRET.equals(decodedKey)) {
				return ;
			}
			
		}
		
		Response unauthorizedResp = Response
						.status(Response.Status.UNAUTHORIZED)
						.entity("User cannot access the resource")
						.build();
		throw new WebApplicationException(unauthorizedResp);
	}
}

The annotation @Provider is required. Without this annotation this filter will not be invoked. Following is my web.xml with Jersey 2. 


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
    id="WebApp_ID" version="3.0">
  <display-name>myapplication</display-name>
  <servlet>
    <servlet-name>jersey-serlvet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>myapplication;common</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>jersey-serlvet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>  
</web-app>

Now my common.SecurityFilter get invoked with Jersey 2. Now my application is working in Jersey 2 as it was working with Jersey 1. Jersey 1 does not work with JDK-17 so you need Jersey 2 for working with JDK-17.