I have a strange java.lang.NullPointerException on a variable that should not be null.
Object[] params = new Object[10];
if (param1 != null)
params[0] = param1;
param1 is given as a method parameter, and it can be null.
Normally, when affecting param1 to params[0], it is not null (otherwise it won't pass the if statement).
Here is the error (line 144 is "params[0] = param1;"):
Exception in thread "Jalen Agent" java.lang.NullPointerException
at jalen.MethodStats.onMethodEntry(MethodStats.java:144)
at hanoi.TowersOfHanoi.solveHanoi(TowersOfHanoi.java)
at hanoi.TowersOfHanoi.main(TowersOfHanoi.java:29)
Here is the full code of the method where the exception occurs:
public static void onMethodEntry(int id, String className, String methodName, Object param1, Object param2, Object param3, Object param4, Object param5) {
synchronized (globalLock) {
Object[] params = new Object[10];
if (param1 != null)
params[0] = param1;
if (param2 != null)
params[1] = param2;
if (param3 != null)
params[2] = param3;
if (param4 != null)
params[3] = param4;
if (param5 != null)
params[4] = param5;
MethodStats.onMethodEntry(id, className, methodName, params);
}
}
EDIT:
To clarify my example, I am in a context of:
Instrument a Java application using ASM
Run the new instrumented classes while using a Java agent
The agent will use information collected by the instrumented code to run some measurements
The agent also collects the values of methods' parameters of the application.
For this, onMethodEntry is executed on each method run. I have several of these methods with different signatures. In particular:
public static void onMethodEntry(int id, String className, String methodName, Object[] params) {
synchronized (globalLock) {
StringBuilder fullMethodName = new StringBuilder(className).append('.').append(methodName).append('-').append(Thread.currentThread().getId());
MethodStats.addNewMethod(id, fullMethodName.toString());
System.out.println(fullMethodName.toString() + " -- " + id);
for (Object param : params) {
if (param != null)
System.out.println("Param: " + param.toString());
}
startTimes[depth] = System.nanoTime();
stack[depth++] = MethodStats.getMethodInfo(id);
}
}
public static void onMethodEntry(int id, String className, String methodName, Object param1) {
synchronized (globalLock) {
Object[] params = new Object[10];
if (param1 != null)
params[0] = param1;
MethodStats.onMethodEntry(id, className, methodName, params);
}
}
public static void onMethodEntry(int id, String className, String methodName, Object param1, Object param2) {
synchronized (globalLock) {
Object[] params = new Object[10];
if (param1 != null)
params[0] = param1;
if (param2 != null)
params[1] = param2;
MethodStats.onMethodEntry(id, className, methodName, params);
}
}
And this is the code I used for instrumenting the program classes (i.e. Tower of Hanoi):
public void visitCode() {
mv.visitLdcInsn(new Integer(this.methodID));
this.visitLdcInsn(this.className);
this.visitLdcInsn(this.methodName);
String paramCall = "";
if (this.numParam > 0) {
// Load parameters
for (int i=1; i<=this.numParam; i++) {
this.visitVarInsn(Opcodes.ALOAD, i);
paramCall += "Ljava/lang/Object;";
}
}
System.out.println(paramCall);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
"jalen/MethodStats",
"onMethodEntry",
"(ILjava/lang/String;Ljava/lang/String;" + paramCall + ")V");
super.visitCode();
}
First, the error is not on the params[0] = param1 line, because the stack trace shows that your code entered the onMethodEntry method.
There is absolutely no point in adding if statements: in case param1 is null, there would be no null assignment, but params[0] would remain null because all unassigned positions in new Object[10] are initially set to null.
In order to fix the problem, you should first figure out what objects must be placed in the array instead of null parameters, and then modify the conditions as follows:
if (param1 != null) {
params[0] = param1;
} else {
params[0] = // something else
}
Why don't you replace your
onMethodEntry(int id, String className, String methodName, Object[] params) {
method with the varargs version:
onMethodEntry(int id, String className, String methodName, Object... params) {
That way, you can get rid of your other methods, which are all the same, just with different amount of parameters. Also the method containing your error would disappear. If the error still persists, you're one step closer to finding it.
Also, you wouldn't have to change any code where you call the method, because it's signature is the same.
Related
I have written java code for the below plsql code to execute stored procedure. I am not getting result when I run the procedure from Java code.
PLSQL
declare
CAMFORMLIST_ID_TY CAMFORMLIST_ID_TYPES;
CAMFORMLIST_ID_T CAMFORMLIST_ID_TYPE;
OFEERS_INFO_TY OFEERS_INFO_TYPE;
begin
CAMFORMLIST_ID_T:=CAMFORMLIST_ID_TYPE('HH','K');
CAMFORMLIST_ID_TY:=CAMFORMLIST_ID_TYPES(CAMFORMLIST_ID_T);
GETOFEERSFROMCAMFORM(CAMFORMLIST_ID_TY,OFEERS_INFO_TY);
for i in OFEERS_INFO_TY.FIRST..OFEERS_INFO_TY.LAST loop
DBMS_OUTPUT.PUT_LINE('Name: '|| OFEERS_INFO_TY(i).OFFER_NAME);
end loop;
end;
My Java Stored Procedure class.
#Component
public class GetOffersFromCAMFORM extends StoredProcedure {
private static final String OFEERS_LIST = "Offers";
#Autowired
private String MySchema;
#Autowired
#Qualifier("MyDataSource")
private DataSource dataSourceMy;
#PostConstruct
public void postConstruct() {
this.setDataSource(dataSourceMy);
this.setSql(MySchema + ".getOffersFromCAMFORM");
declareParameter(new SqlParameter(SUB_FORM, Types.ARRAY, MySchema + ".CAMFORMLIST_ID_TYPES"));
declareParameter(
new SqlOutParameter(OFEERS_LIST, OracleTypes.ARRAY,
MySchema + ".OFEERS_INFO_TYPE", new ReturnType()));
}
#SuppressWarnings("unchecked")
public List<MyOffer> execute(final String subscriptionForm, final String subscriptionClass)
throws Exception {
Map<String, Object> objects = new HashMap<String, Object>();
objects.put(SUB_FORM, new AbstractSqlTypeValue() {
#Override
protected Object createTypeValue(Connection con, int SqlType, String typeName)
throws SQLException {
OracleConnection oracle =
(OracleConnection) (new DelegatingConnection(con)).getInnermostDelegate();
if (oracle != null) {
con = oracle;
}
ArrayList<Struct> CAMFORMListIdType = new ArrayList<Struct>();
CAMFORMListIdType
.add(((OracleConnection) con).createStruct(MySchema + ".CAMFORMLIST_ID_TYPE",
new String[] {subscriptionForm, subscriptionClass}));
return ((OracleConnection) con).createARRAY(MySchema + ".CAMFORMLIST_ID_TYPES",
CAMFORMListIdType.toArray(new Struct[] {}));
}
});
Map<?, ?> result = execute(objects);
List<MyOffer> items = (List<MyOffer>) result.get(OFEERS_LIST);
return items;
}
}
Return type
public class ReturnType implements SqlReturnType {
#Override
public List<PCOffer> getTypeValue(CallableStatement cs, int colIndx, int sqlType,
String typeName) throws SQLException {
Array dba = (Array) cs.getObject(colIndx);
if (dba == null || ((Object[]) dba.getArray()).length == 0) {
return null;
}
...
}
Ojdbc 7 driver is used.
I am not getting the output. When I execute the procueudre, I get empty array in ReturnType class.
Am I doing something wrong.
SITUATION
In the code below you can see 2 REST services which both should return a MessageVO. The first service (serviceThatDoesWork) returns a MessageVO as excpected, but the second service (serviceThatDoesNotWork) refuses to, it doesn't even give any output at all.
However returning a Response (java.ws.rs.core.Response) with serviceThatDoesNotWork does give an output. Even when I skip the 'doStuff'-methods and create a dummy-MessageVO that is exactly the same for each service, the 2nd one doesn't return anything.
QUESTION
Why does the 2nd service fail to return a MessageVO? It doens't return anything when I try returning a MessageVO, and nothing out of the ordinary appears in the logging.
The two services need to return exactly the same kind of thing but still one of them doesn't want to return anything, what am I not seeing here?
Could it be because of the path (and/or the amount of parameters)?
CODE
MyServices.java:
#Path("/myService")
...
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/myPath/{param1}/{param2}/{param3}")
public MessageVO serviceThatDoesWork(#PathParam("param1") Integer param1_id, #PathParam("param2") Integer param2_id, #PathParam("param2") Integer param2_id)
{
List<SomethingVO> lstO = MyRestServiceBusiness.doStuff(param1_id, param2_id, param3_id);
//return SUCCESS or FAIL message
MessageVO msg = new MessageVO();
if(lstO.size() > 0)
{
List<String> s = new ArrayList<String>();
for(SomethingVO k : lstO)
{
s.add(k.getId().toString());
}
msg.setItem_ids(s);
msg.setMsg("SUCCESS");
}
else
{
msg.setMsg("FAIL");
}
return msg;
}
...
#GET
#Path("/myPath/{param1}/{param2}/{param3}/{param4}/.../{param15}{a:(/a/[^/]+?)?}{b:(/b/[^/]+?)?}")
public Response serviceThatDoesNotWork(#PathParam("param1")Integer param1_id, ..., #PathParam("param15") Integer param15_id,
#PathParam("a") String a_id, #PathParam("b") String b_id)
{
//PUT 'OPTIONAL' PARAMS IN A LIST
List<Integer> lstI = new ArrayList<Integer>();
String aId = a_id != null ? a_id.split("/")[2] : null;
String bId = b_id != null ? b_id.split("/")[2] : null;
if(aId != null)
{
lstI.add(Integer.parseInt(aId ));
}
if(bId != null)
{
lstI.add(Integer.parseInt(bId ));
}
//DO STUFF
String afsId = "";
if(lstI.size() > 0)
{
afsId = MyRestServiceBusiness.doStuff(param1, ..., lstI);
}
//return SUCCESS or FAIL message
MessageVO msg = new MessageVO();
if(afsId != null && !afsId.isEmpty())
{
List<String> s = new ArrayList<String>();
s.add(afsId);
msg.setItem_ids(s);
msg.setMsg("SUCCESS");
}
else
{
List<String> s = new ArrayList<String>();
for(Integer i : lstI)
{
s.add(i.toString());
}
msg.setItem_ids(s);
msg.setMsg("FAIL");
}
//WENT THROUGH ALL ABOVE CODE AS EXPECTED, MESSAGEVO HAS BEEN FILLED PROPERLY
return msg;
}
CODE MessageVO.java:
#XmlRootElement
public class MessageVO
{
private String msg;
private List<String> item_ids;
//GETTERS
#XmlElement(name = "Message")
public String getMsg() {
return msg;
}
#XmlElement(name = "Item ID's")
public List<String> getItem_ids() {
return item_ids;
}
//SETTERS
public void setMsg(String msg) {
this.msg = msg;
}
public void setItem_ids(List<String> item_ids) {
this.item_ids = item_ids;
}
If I need to provide extra information please ask, this is my first attempt at (REST-) services.
As Vaseph mentioned in a comment I just forgot the #Produces annotation in the 2nd service.
I am playing around with JGroups as a distributed system. I want to create objects on a remote JVM and use them as if they were created locally. Therefore I am using a java.lang.reflect.Proxy to wrap the RPC calls. This is a much like RMI behavior. This works very well.
But now I want to garbage collect the remote object if the client interface/proxy is no longer in use. So I thought I can get this working by using a WeakReference but I never fall into the GC cycle. What am I missing?
public class RMILikeWrapper {
private static final ScheduledExecutorService garbageCollector = Executors.newSingleThreadScheduledExecutor();
private final Map remoteObjects = new ConcurrentHashMap();
private final Map<WeakReference, IdPointer> grabageTracker = new ConcurrentHashMap<>();
private final ReferenceQueue rq = new ReferenceQueue();
private final RpcDispatcher rpcDispatcher;
private final long callTimeout = 10000L;
private class IdPointer {
public final Address address;
public final String id;
public IdPointer(Address address, String id) {
this.address = address;
this.id = id;
}
#Override
public String toString() {
return "IdPointer{" + "address=" + address + ", id='" + id + '\'' + '}';
}
}
public RMILikeWrapper(Channel channel) {
this.rpcDispatcher = new RpcDispatcher(channel, null, null, this);
// enable garbage collecting
garbageCollector.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
System.out.println("my GC ");
Reference<?> ref; //this should be our weak reference
while((ref = rq.poll()) != null) {
// remove weak reference from the map
IdPointer garbage = grabageTracker.remove(ref);
System.out.println("found expired weak references: " + garbage);
// now we need to destroy the remote object too
try {
rpcDispatcher.callRemoteMethod(garbage.address, "purge", new Object[]{garbage.id},
new Class[]{String.class}, new RequestOptions(ResponseMode.GET_FIRST, callTimeout));
} catch (Exception e) {
e.printStackTrace();
}
}
}
},0,10, TimeUnit.SECONDS);
}
public <T>T createRemoteObject(Class<T> proxyInterface, Address targetNode, Class c, Object[] args, Class[] argTypes) {
try {
Object[] remoteArgs = new Object[4];
remoteArgs[0] = UUID.randomUUID().toString();
remoteArgs[1] = c;
remoteArgs[2] = args;
remoteArgs[3] = argTypes;
rpcDispatcher.callRemoteMethod(targetNode, "addObject", remoteArgs,
new Class[]{String.class, Class.class, Object[].class, Class[].class},
new RequestOptions(ResponseMode.GET_FIRST, callTimeout));
// now get in interface stub for this object
return getRemoteObject(targetNode, remoteArgs[0].toString(), proxyInterface);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// Operation triggerd by RPC
public void addObject(String id, Class c, Object[] args, Class[] parameterTypes) throws Exception {
remoteObjects.put(id, c.getConstructor(parameterTypes).newInstance(args));
}
// Operation triggerd by RPC
public Object invoke(String id, String methodName, Object[] args, Class[] argTypes) throws Exception {
Object ro = remoteObjects.get(id);
return ro.getClass().getMethod(methodName, argTypes).invoke(ro, args);
}
// Operation triggerd by RPC
public void purge(String id) {
System.out.println("garbage collecting: " + id);
//return remoteObjects.remove(id) != null;
remoteObjects.remove(id);
}
public <T>T getRemoteObject(final Address nodeAdress, final String id, final Class<T> clazz) {
if (!clazz.isInterface()) throw new RuntimeException("Class has to be an interface!");
InvocationHandler handler = new InvocationHandler() {
#Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
Object[] remoteArgs = new Object[4];
remoteArgs[0] = id;
remoteArgs[1] = method.getName();
remoteArgs[2] = args;
remoteArgs[3] = method.getParameterTypes();
// remote call
return rpcDispatcher.callRemoteMethod(nodeAdress, "invoke",
remoteArgs, new Class[]{String.class, String.class, Object[].class, Class[].class},
new RequestOptions(ResponseMode.GET_FIRST, callTimeout));
}
};
T result = (T) Proxy.newProxyInstance(
clazz.getClassLoader(),
new Class[]{clazz},
handler);
// use weak pointers to the proxy object here and if one is garbage collected, purge the remote object as well
WeakReference<T> weakReference = new WeakReference<>(result, rq);
grabageTracker.put(weakReference, new IdPointer(nodeAdress, id));
return result;
}
public static void main(String[] args) throws Exception {
Channel channel = new JChannel();
channel.connect("test-cluster");
List<Address> members = channel.getView().getMembers();
RMILikeWrapper w = new RMILikeWrapper(channel);
if (members.size() > 1) {
System.out.println("send to " + members.get(0));
FooInterface remoteObject = w.createRemoteObject(FooInterface.class, members.get(0), FooImpl.class, null, null);
System.out.println(remoteObject.doSomething("Harr harr harr"));
remoteObject = null;
}
System.out.println(channel.getView().getMembers());
}
}
Using following methods you could identify how GC behaves on weak references.
Option 1:
-verbose:gc
This argument record GC behaviour whenever GC kicks into picture. You could take the log file when you want to check did GC gets into action, It could be checked from the GC logs. For Interactive GC analysis try the log with http://www.ibm.com/developerworks/java/jdk/tools/gcmv/
Option 2 :
Collect Heap dump and user event and load it in https://www.ibm.com/developerworks/java/jdk/tools/memoryanalyzer/
Write OQL(Object Query language) on OQL section
select * from package(s).classname
and click on ! on the tool bar
It will give list of objects of that type
Right click on the objects -> Path to GC roots -> Exclude soft/weak/Phantom references
If suspect object does not have any strong reference then it will show NULL else
you will get information on who is holding the strong references on the suspected object.
I have created EasyMock test cases for one method which has method.invoke().One test case runs fine with this code.The second one which should cover the first "if" condition creates this IlegalArguent Exception:Wrong number of arguments.I don't understand which one is incorrect.whether original code or test case.
Please help.
Original code:
#RequestMapping(value = "/invoke/{service}/{method}", method = RequestMethod.POST)
public #ResponseBody
Object invokeService(#PathVariable("service") String className,
#PathVariable("method") String method,
#RequestParam("ms") String signature,
#RequestParam("r") String responseType, #RequestBody String[] body)
throws Exception {
if (applicationContext != null
&& applicationContext.containsBean(className)) {
Object obj = applicationContext.getBean(className);
String temp[] = signature.split(",");
Object[] arguments = new Object[temp.length];
Class[] parameterTypes = new Class[temp.length];
for (int i = 0; i < temp.length; i++) {
if(temp[i] != null && !temp[i].isEmpty()) {
Class cls = Class.forName(temp[i]);
parameterTypes[i] = cls;
if (temp[i].startsWith("java.lang.")) {
arguments[i] = body[i];
} else {
try {
arguments[i] = mapper.readValue(body[i], cls);
} catch (Exception e) {
// e.printStackTrace();
arguments[i] = body[i];
}
}
}
}
Method m = null;
if(null !=signature && !signature.isEmpty()) {
m = obj.getClass().getMethod(method, parameterTypes);
} else {
m = obj.getClass().getMethod(method);
}
Object response = m.invoke(obj);
return response;
} else {
throw new Exception("ApplicationContext not properly set");
}
}
Test1(success):
#Test
public void testInvokeServiceNotJavaLang() throws Exception{
Object obj = new Object();
String[] body ={ "body" };
EasyMock.expect(applicationContext.containsBean("String")).andReturn(true);
EasyMock.expect(applicationContext.getBean("String")).andReturn(obj);
EasyMock.replay(applicationContext);
moduleInvocation.invokeService("String", "toString","", "responseType",body );
EasyMock.verify(applicationContext);
}
Test2(IllegalArgumentException:Wrong number of arguments)
#Test
public void testInvokeService() throws Exception{
Object obj = new Object();
String[] body ={ "body" };
EasyMock.expect(applicationContext.containsBean("Object")).andReturn(true);
EasyMock.expect(applicationContext.getBean("Object")).andReturn(obj);
EasyMock.replay(applicationContext);
moduleInvocation.invokeService("Object", "equals", "java.lang.Object", "responseType",body );
EasyMock.verify(applicationContext);
}
Problem is with your code, In first case you are calling a method String#toString() which does not have any parameters and it gets called successfully. In second case you are calling Object#equals() method which expects one argument as well so you need to pass that argument value as well while using m.invoke(), so your code should be for second case
m.invoke(obj,new Object[]{<object to be compared>});
and for fist case this will suffice
m.invoke(obj,null);
Hope this helps.
EDIT
You should write it something like this:
Method m = null;
if(null !=signature && !signature.isEmpty()) {
m = obj.getClass().getMethod(method, parameterTypes);
} else {
m = obj.getClass().getMethod(method);
arguments = null;
}
Object response = m.invoke(obj, arguments);
return response;
I have a filter that takes an incoming request, and then wraps it with an HttpServletRequestWrapper, which in turn has a setParameter() method on it. However, this will no longer work now in any filtered servlets:
<jsp:include page="testing-include.jsp">
<jsp:param name="testing" value="testing" />
</jsp:include>
The include page will not take the request parameter. If I remove the filter, and the original unmodified request is sent (unwrapped) to the servlet, then it works again. Here is my wrapper:
public class HttpServletModifiedRequestWrapper extends HttpServletRequestWrapper {
Map parameters;
#SuppressWarnings("unchecked")
public HttpServletModifiedRequestWrapper(HttpServletRequest httpServletRequest) {
super(httpServletRequest);
parameters = new HashMap(httpServletRequest.getParameterMap());
}
public String getParameter(String name) {
String returnValue = null;
String[] paramArray = getParameterValues(name);
if (paramArray != null && paramArray.length > 0){
returnValue = paramArray[0];
}
return returnValue;
}
#SuppressWarnings("unchecked")
public Map getParameterMap() {
return Collections.unmodifiableMap(parameters);
}
#SuppressWarnings("unchecked")
public Enumeration getParameterNames() {
return Collections.enumeration(parameters.keySet());
}
public String[] getParameterValues(String name) {
String[] result = null;
String[] temp = (String[]) parameters.get(name);
if (temp != null){
result = new String[temp.length];
System.arraycopy(temp, 0, result, 0, temp.length);
}
return result;
}
public void setParameter(String name, String value){
String[] oneParam = {value};
setParameter(name, oneParam);
}
#SuppressWarnings("unchecked")
public void setParameter(String name, String[] values){
parameters.put(name, values);
}
}
I'm really having trouble determining what could be happening without looking at Tomcat's implementation source for the jsp:include and jsp:param standard actions, but there must be some conflict there. Any help would be appreciated.
I guess the problem is that your wrapper doesn't provide access to the new parameters, which were added to the original parameter map after you copied it.
Probably, you should do something like this (and in the other methods, too):
public String[] getParameterValues(String name) {
String[] result = null;
String[] temp = (String[]) parameters.get(name);
if (temp != null){
result = new String[temp.length];
System.arraycopy(temp, 0, result, 0, temp.length);
} else {
return super.getParameterValues(name);
}
return result;
}