Accessing static constant arrays from Jtwig template - java

So, I simply cannot gather access to values in constant static arrays.
Let this be an array in my code:
public static int[] MY_ARRAY;
And this is how i trying to access that array:
{{ constant("com.package.configs.MainConfig.MY_ARRAY")[0] }}
This attempt leads to an error:
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
at org.jtwig.value.convert.collection.ArrayToCollectionConverter.convert(ArrayToCollectionConverter.java:11)
at org.jtwig.value.convert.CompositeConverter.convert(CompositeConverter.java:15)
at org.jtwig.render.expression.calculator.MapSelectionExpressionCalculator.calculate(MapSelectionExpressionCalculator.java:19)
at org.jtwig.render.expression.calculator.MapSelectionExpressionCalculator.calculate(MapSelectionExpressionCalculator.java:12)
at org.jtwig.render.expression.CalculateExpressionService.calculate(CalculateExpressionService.java:14)
...
I also tried to assign a constant to variable first, then accessing it, but nothing changed.
Previously, in an older versions of JTwig i was able to access any public static field of a object that i passed to the model. But now such fields are being ignored.
The version i am using is 5.86.0.
Any idea on how to beat this, or at this moment it's technically impossible?

The exception
java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
means the array MY_ARRAY is an int-type array, and int is a primitive, thus it's not a sub type of Object, so you can not cast it to an Object-type array.
In this case, you can change MY_ARRAY's Signature to public static Integer[] MY_ARRAY.
Integer wraps the int value in an Object.
This is illustrated by the following example:
public static void main(String args[]) {
int[] arr = new int[5];
Integer[] arrI = new Integer[5];
test(arr); // error:The method test(Object[]) in the type Demo is not applicable for the arguments (int[])
test(arrI); // ok
}

Related

Why can I declare a generic array but not initialize it?

Imagine this two sample codes:
public class TestCompile<T> {
private T[] array;
public static void main(String[] args) {
}
}
public class TestNoCompile<T> {
private T[] array = new T[5];
public static void main(String[] args) {
}
}
The first class TestCompile has no errors at compilation time and the second one TestNoCompile is not able to compile.
I understant why the second one doesnt compile since the arrays in Java are covariant and the type erasure is not compatible with that. But I cant understant why the first example compiles, why can I declare a generic array if then I cant initialize it?
On the other hand I cant unserstant this other example:
public class Example<T> {
private T[] array;
public static void main(String[] args) {
Example<Integer> example = new Example<>();
example.method(new Integer[5]);
}
public void method(T[] array) {
array[0] = 1; //This line doesnt compile.
}
Here it seems Im able to initialize a generic array in the method method(...) but then Im not able to store any value in it. Which is the explanation of this behaviour?
There's nothing wrong with the type T[] itself. It's perfectly fine to have a variable of type T[] and you can assign any value of type T[] to that variable fine, without any warnings. The question is how do you get a value of type T[].
I think you've answered your own question later when you showed that, for example, you can have a value of type T[] passed in from the outside, into a method (or a constructor) of your class. And in the caller's scope in your example, T is a concrete type (Integer), so the caller can create a T[] in its scope fine and pass it in.
As you have found, you can't create a value of type T[] (other than null) without a warning inside the class (where T is generic). This is because arrays know their component type at runtime (because arrays in Java check at runtime every element that is stored into the array is an instance of the component type), so to create an array object, you need to provide the component type of the array you want to create at runtime, and inside the class, you don't know what T is at runtime. So new T[5] is not a valid expression.
In Andreas's answer, they create an array of type Object[], and then cast it to T[], but this is basically lying to the compiler. Obviously, if T is any type other than Object, this cast is incorrect. For example, String[] foo = (String[]) new Object[5]; throws a class cast exception at runtime. However, T is erased to Object inside the class, so it does not immediately throw a class cast exception. You get an unchecked cast warning to warn you that you might not get an exception even if the cast is incorrect, so you may have a variable whose compile-time type is incompatible with its runtime type, and you may unexpectedly get a class cast exception somewhere else later. For example, if you have a method that returns the array to the outside of the class as type T[], and the place outside the class has a concrete type for T, it will cause a class cast exception where there is no cast:
public class Example<T> {
private T[] array = (T[]) new Object[5];
public T[] getArray() {
return array;
}
public static void main(String[] args) {
Example<Integer> example = new Example<>();
Integer[] foo = example.getArray(); // class cast exception
}
}
Your statement that you cannot store any value in the array is incorrect. You can store values in it, but you can only store values of type T. Inside the class, you don't know what T is, so where are you going to get a value of type T? You would either have to use null, or you have to get it from outside the class:
public class Example<T> {
private T[] array;
public Example(T[] a) {
array = a;
}
public void set(int i, T x) {
array[i] = x;
}
public static void main(String[] args) {
Example<Integer> example = new Example<>(new Integer[5]);
example.set(0, 1);
}
}
Because of type-erasure, a generic array becomes an Object[] at runtime, so you need to create it as such, cast it, and acknowledge that what you're doing is not safe:
#SuppressWarnings("unchecked")
private T[] array = (T[]) new Object[5];
As for the array[0] = 1 statement, the problem is that array is a T[], and that T can be anything, so the code isn't valid.
What is you changed the code in main as follows?
Example<String> example = new Example<>();
example.method(new String[5]);
The array[0] = 1 statement is now obviously not valid, and remember, declaring a Example<String> could easily be done elsewhere at the same time you have Example<Integer> in main.
The code in method must be value for all possible T's.

Failed to pass array as parameter in java

I have a method doSomething() which accept Array as parameter. When I pass array like bellow:
package org.my;
public class ArrayMistry {
public static void main(String ... args) {
doSomething({1,2});// Compilation Error
}
public static void doSomething(int[] params) {
}
}
I am getting compilation error:
Exception in thread "main" java.lang.Error: Unresolved compilation
problems: Syntax error on token "doSomething", # expected before
this token Syntax error, insert "enum Identifier" to complete
EnumHeader Syntax error, insert "EnumBody" to complete
BlockStatements
at org.my.ArrayMistry.main(ArrayMistry.java:6)
Note:
if I pass as bellow then its OK:
public static void main(String ... args) {
int[] p = {1,2};
doSomething(p);// no Error
doSomething(new int[]{1,2});// no Error
}
Arrays are passed by reference. You need to create an array object with [1,2] and pass the reference of that created object to dosomething. The new keyword allocates space for the creation of this int array.
int[] arr = new int[]{1,2};
doSomething(arr);
It's because you aren't declaring {1, 2} as a new array. It must be declared as new int[]{1,2} to function properly, otherwise you are not creating an array.
You have to make an array to pass into a method because you initialized the method that way. The reason this doSomething({1,2}); doesn't work is because the array has not been initialized and {1, 2} is not an array, it is just some numbers in a parenthesis. if you wanted to send an array you have to do something like this
int[] p = {1,2};
doSomething(p);
Your method doSomething() specifically accepts an array of integers as its parameters.
Note in both cases where it worked, you either passed an existing array, or created a new one when passing it in.
In your original example, you are passing an arbitrary set of numbers with no memory reserved, or type specified.
Another way to solve the problem is by passing a reference as a parameter to the function like this:
doSomething(new int[]{1,2});

How do I use an array that is of another class type?

I have declared a class named Member. I then assigned an array with Member type. When I try to put things into the array, it gives me this error:
Exception in thread "main" java.lang.NullPointerException
at HW2_2.main(HW2_2.java:15)
This is my code:
import c.Member;
import java.util.Scanner;
public class HW2_2
{
public static void main(String []args)
{
Member[] p = new Member[100];
Scanner in = new Scanner(System.in);
p[0].setID("apple12");
p[0].setPassword("1234");
p[0].setFirstname("fname");
p[0].setLastname("lname");
p[0].setEmail("*#gmail.com");
}
}
How do I fix this to the point where I can store data into my array?
You have created an object p which points to an array of Member objects. This is perfect. However, each object in your array is by default null. You cannot simply perform operations on them.
You probably want to do something like...
//...
p[0] = new Member(...);
p[0].setId("ID");
//... And so on
What's important to learn from here is that an array declaration syntax does not initialize the values of the array itself. That would be impossible, right? How would you pass arguments to the constructors of each one seperately? You have to do it manually.
When you:
Member[] p = new Member[100];
it initializes all array members to null (since this is an array of object types).
You need to initialize members if you want them to be usable, therefore here you have to:
p[0] = new Member();
before you can use that member.
If you want to initialize all members at once, you need to loop over all elements in the array and create one for each member; with Java 8 this can be done as such:
IntStream.range(0, p.length).forEach(index -> p[index] = new Member());
Curiously enough, there is no such method as <T> void fill(T[] array, Supplier<T> supplier) in the Arrays class.

In which condition which overloaded version of toArray() and toArray(T[] a) should be use?

I never use overloaded version of toArray Object[] toArray(Object[] a) to convert collection into array.
below is my javacode-
public class Track {
public static void main(String x[]) {
ArrayList<String> iName = new ArrayList<String>();
iName.add("Arpit1");
iName.add("Arpit2");
iName.add("Dubey1");
iName.add("Dubey2");
Object[] array= iName.toArray();
for(int i=0;i<array.length;i++)
System.out.println(array[i].getClass());
}
}
Output-
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String
Expected-
class java.lang.Object
there are some other question related this I go through all but no one pointing my query.
You need to use the overloaded method to get an array of the appropriate type. Otherwise the returned array will always be of type Object[].
Your code - which uses the toArray() method without parameters - returns an object array which cannot be cast to an array of another type and thus will throw an exception:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
Before going any further, whatever may be the result of your toArray method, the elements of the array will always remain of type String.
for(int i=0;i<array.length;i++)
System.out.println(array[i].getClass());
Thus, this will always return class java.lang.String.
You may expect that the elements will be converted to Object if you store them in an Object[], but that's not the case. The array is just the container.
That being said, the paramater of the toArray indicates the type of the array to be constructed. So, you could store a list of Integers in a Number[] array.

Java array pass without reference

I am trying to pass an array without using a reference, but directly with the values :
public static void main(String[] args){
int[] result = insertionSort({10,3,4,12,2});
}
public static int[] insertionSort(int[] arr){
return arr;
}
but it returns the following exception :
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
Syntax error on token(s), misplaced construct(s)
Syntax error on token ")", delete this token
When I try the following code , it works , can anybody please explain the reason ?
public static void main(String[] args){
int[] arr = {10,3,4,12,2};
int[] result = insertionSort(arr);
}
public static int[] insertionSort(int[] arr){
return arr;
}
It has to be
int[] result = insertionSort(new int[]{10,3,4,12,2});
{10,3,4,12,2} is a syntactic sugar for array initialization, which must go with the declaration statement like the one in the following -
int[] arr = {10,3,4,12,2};
Something as follows is not allowed too -
int[] arr; // already declared here but not initialized yet
arr = {10,3,4,12,2}; // not a declaration statement so not allowed
insertionSort({10,3,4,12,2})
is not valid java because you don't specify a type in your method call.
The JVM does not know what type of array this is. Is it an array with double values or with int values?
What you can do is insertionSort(new int[]{10, 3 ,4 12, 2});
int[] array = { a, b, ...., n } is a shorthand initialization - you have to write:
int[] result = insertionSort(new int[]{10,3,4,12,2});
to initialize it anonymously.
Nothing much to add to what others said.
However I believe the reason why you should use new int[]{10,3,4,12,2} (like others stated) and Java doesn't let you use just {10,3,4,12,2} is that Java is strong typed.
If you just use {10,3,4,12,2} there is no clue of what the type of the array elements can be. They seem to be integers, but they can be int, long, float, double, etc...
Well, actually it might infer the type from the method signature, and fire a compile error if it doesn't fit, but it seems complicated.

Categories