Why can't I cast an object to collection in Java? - java

I am writing a Unit Test for a class as follows:
#Test
void testCreateStackResources()
{
List<StackResource> stackResourceListExpected = new ArrayList<>();
StackResource stackResource = new StackResource();
stackResource.setLogicalResourceId("Sample-Logical-ID");
stackResourceListExpected.add(stackResource);
ListStackResourcesResult listStackResourcesResult = new ListStackResourcesResult();
StackResourceSummary stackResourceSummary = new StackResourceSummary();
stackResourceSummary.setLogicalResourceId("Sample-Logical-ID");
listStackResourcesResult.setStackResourceSummaries((Collection<StackResourceSummary>) stackResourceSummary); // Problem in this line
Mockito.when(amazonCloudFormation.listStackResources(Mockito.any(ListStackResourcesRequest.class))).thenReturn(listStackResourcesResult);
List<StackResource> stackResourceListResult = cloudFormationManager.createStackResources(Mockito.anyString());
Assert.assertEquals(stackResourceListExpected, stackResourceListResult);
}
Now, when I run this code, it gives me an error that I can't cast StackResourceSummary to a Collection in Java.
java.lang.ClassCastException: com.amazonaws.services.cloudformation.model.StackResourceSummary cannot be cast to java.util.Collection
On the other hand, if I make an array list before, add the object of StackResourceSummary to the list and then run the UT, it gives me the
objc[3648]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/bin/java (0x10d19c4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10ea194e0). One of the two will be used. Which one is undefined.
This is very weird behaviour. I don't know why can't I cast this to a collection? Please help. Thanks!
PS: There is a seperate class called ListStackResourcesResult which has a setter as follows:
public void setStackResourceSummaries(java.util.Collection<StackResourceSummary> stackResourceSummaries) {
if (stackResourceSummaries == null) {
this.stackResourceSummaries = null;
return;
}
this.stackResourceSummaries = new com.amazonaws.internal.SdkInternalList<StackResourceSummary>(stackResourceSummaries);
}
And I am trying to use this method above.

That is because StackResourceSummary does not extend or implement anything related to a collection.
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudformation/model/StackResourceSummary.html
What you need to to is create a collection and add your instance of StackResourceSummary to it. For example like so:
List<StackResourceSummary> stackResourceSummaries = new ArrayList<StackResourceSummary>();
stackResourceSummaries.add(stackResourceSummary)
or maybe like so
Arrays.asList(stackResourceSummary)
or use a third party lib like guava collections.
Then you should use that collection as an argument.
listStackResourcesResult.setStackResourceSummaries(stackResourceSummaries); // Problem gone in this line

Related

Java List auto create and add

Is it possible to replace this:
if (archiveUnitEntity.getArchiveCaseEntityList() == null) {
archiveUnitEntity.setArchiveCaseEntityList(new ArrayList<ArchiveCaseEntity>());
}
archiveUnitEntity.getArchiveCaseEntityList().add(archiveCaseEntity);
This something like that:
ifListNullCreate(archiveUnitEntity.getArchiveCaseEntityList()).Add(archiveCaseEntity);
If you can change the method getArchiveCaseEntityList() then you could add that null check into the getter and update it there (or create another method if you need it to be null in some cases). If not, then you could create the method you want wherever you want/need.
But I don't think there is a built-in method to do that.
Here's one possible solution.
In the ArchiveUnitEntity class, declare the list like this, so that it's not null on creation.
private List<ArchiveCaseEntity> archiveCaseEntityList = new ArrayList<>();
You might also want to change the setter for that field, so that it can't get set to null.
public void setArchiveCaseEntityList(ArchiveCaseEntityList archiveCaseEntityList) {
this.archiveCaseEntityList = archiveCaseEntityList == null ? new ArrayList<ArchiveCaseEntity>() : archiveCaseEntityList;
}
It's better to initialize your archiveCaseEntityList attribute during the creation of the instance of archiveUnitEntity. Avoiding null object can simplify a lot of things :)
Directly when you declare your attribute :
private List<ArchiveCaseEntity> archiveCaseEntityList = new ArrayList<>();
or in constructor :
public ArchiveUnitEntity(){
this.archiveCaseEntityList = new ArrayList<>();
}
And finally, you could build a new method to manage ArchiveCaseEntity addition :
public void addArchiveCaseEntity(ArchiveCaseEntity entity){
this.archiveCaseEntityList.add(entity);
}

Initializing empty instance variables in constructor

I have a LogAnalyzer class that looks at a web server log, creates LogEntry objects and puts those objects into HashMaps for analyzing.
My LogAnalyzer class has these fields:
private int totalVisits;
private int uniqueVisits;
private ArrayList<LogEntry> records;
private HashMap<String, ArrayList<LogEntry>> uniqueIPs; //<address, log entries>
private HashMap<String, ArrayList<LogEntry>> dailyRecords; // <date, log entries>
My constructor looks like this:
public LogAnalyzer() {
records = new ArrayList<>();
dailyRecords = new HashMap<>();
uniqueIPs = new HashMap<>();
}
And then I have this method:
public void initializeRecords(String path){
readFile(path); //reads the web log file and fills out the records and dailyRecords fields
getUniqueIPs(); //fills out the uniqueIPs HashMap field.
uniqueVisits = uniqueIPs.size(); //fills out the uniqueVisits field
totalVisits = records.size(); //fills out the totalVisits field
}
So my question:
I have read (but don't really understand) it's "bad" to call methods inside the constructor. However it seems like the constructor is pointless here, since it is actually the initializeRecords that is doing all of the meaningful work of "creating" the object.
I don't have the background in Java or programming to understand the explanations I've found so far. There is a lot of talk of overriding things, and I think that's what I'm not clear on. I'm wondering why I should keep my constructor and this method seperated, in simple terms that a beginner can understand.
**EDIT: ** Here's the code for readFile():
public void readFile(String filename) {
FileResource fr = new FileResource(filename);
for (String line : fr.lines()){
LogEntry le = WebLogParser.parseEntry(line);
String date = le.getAccessTime().toString().substring(4, 10);
if (dailyRecords.keySet().contains(date)){
dailyRecords.get(date).add(le);
}
else{
ArrayList<LogEntry> entries = new ArrayList<>();
entries.add(le);
dailyRecords.put(date, entries);
}
records.add(le);
}
Keeping the two methods allows you more flexibility in the use of your code. You can instantiate your LogAnalyzer without knowing the path to your log. I would rename initializeRecords to processRecords which IMO is more descriptive of what you are doing there.
We should create the object first and then call methods on it. If your readFile method were to throw an Exception because it can't read the file for example. I would find it very odd to get that exception when I am constructing the object. The point of the constructor is to provide an object that can be used to do something.
It's not a good practice to call methods from within constructor, because Java always calls the most derived method, which means we could call a method on a half-initialized object.
To answer your question,
public LogAnalyzer() {
records = new ArrayList<>();
dailyRecords = new HashMap<>();
uniqueIPs = new HashMap<>();
}
What the above part exactly does is, it gives the variables, records, dailyRecods and uniqueIPs a physical address in the memory stack.
When we write something like private ArrayList<LogEntry> records; in the class, at this time only a reference is generated, but actual initialization happens only when records = new ArrayList<>(); this line gets executed.
Hope this clarifies your doubt!!!
As you can see in readFile() it uses the following instruction
dailyRecords.keySet().contains(date)
without initializing dailyRecords prior to it. So if you do not initialize dailyRecords either while declaring it or in constructor you will face NullPointerException.
In your case instead of using constructor for initialization you can use declaration part like this
private HashMap<String, ArrayList<LogEntry>> dailyRecords = new HashMap<>();

Java - Remove "Optional" from a variable (convert)

for a piece of homework, I have to set a variable. The set method given to me, converts that into "Optional". However, I have to store this variable in an ArrayList which doesn't allow Optional variables.How can I convert the variable so it is no longer Optional?
The set method:
public void setParentVertex(IVertex<T> parentVertex)
{
if(parentVertex == null)
this.parentVertex = Optional.empty();
else
this.parentVertex = Optional.of(parentVertex);
}
Where I'm trying to use it:
ArrayList<IVertex<T>> path = new ArrayList<IVertex<T>>();
IVertex<T> parent = current.getLabel().getParentVertex();
path.add(parent);
The error I keep receiving is: "Error: incompatible types: Optional> cannot be converted to IVertex" due to the line where I declare the variable "parent".
Thank you.
Here is the correct version
List<IVertex<T>> path = new ArrayList<IVertex<T>>();
current.getLabel().getParentVertex().ifPresent(path::add)
Also it would be good to rewrite setParentVertex function:
public void setParentVertex(IVertex<T> parentVertex) {
this.parentVertex = Optional.ofNullable(parentVertex);
}
I think you don't have to add it to your list, if there is no value. So just do
if(nameOfOptional.isPresent()){
list.add(nameOfOptional.get());
}
First, add a check to find the value is present or not (by calling isPresent()) and then if the value is present then add to your ArrayList path object as shown below:
ArrayList<IVertex<T>> path = new ArrayList<>();
Optional<IVertex<T>> parent = current.getLabel().getParentVertex();
if(parent.isPresent()) {
path.add(parent.get());
}
or the shorter form is shown below which uses ifPresent method:
ArrayList<IVertex<T>> path = new ArrayList<>();
Optional<IVertex<T>> parent = current.getLabel().getParentVertex();
parent.ifPresent(path::add);
Also, I suggest you have a look at the Optional API methods here.
As a side note, I recommend you to use diamond <> operator while declaring generic types (like shown above i.e., new ArrayList<>()) , so that your code will be less verbose.

How to mock DynamoDB batch save?

I wrote the dynamoDB code which stores list of items.
mapper.batchSave(trafficSensorReadings)
This will return.
List<FailedBatch>
I want to mock the mapper.batchSave and then return one failed job. How can I achieve it? I am using mockito and Junit.
I wrote something like this. But not useful.
when(dynamoDBMapper.batchSave(eq(List.class))).thenReturn(mock(List.class));
A complete example follows
#Test
public void test() {
FailedBatch failedBatch = mock(FailedBatch.class);
List<FailedBatch> failedBatchList = new ArrayList<>();
failedBatchList.add(failedBatch);
DynamoDBMapper dynamoDBMapperMock = mock(DynamoDBMapper.class);
when(dynamoDBMapperMock.batchSave(any(List.class))).thenReturn(failedBatchList);
tested.testedMethodCall();
verify(dynamoDBMapperMock).batchSave(any(List.class));
}
First, I think you might want to use Mockito.any() instead of Mockito.eq().
Second, I don't see why you would want to mock the list. You can just create one and return it
// GIVEN
FailedBatch batch1 = /**/;
FailedBatch batch2 = /**/;
List<FailedBatch> failedBatchList = Lists.newArrayList(batch1, batch2);
// WHEN
when(dynamoDBMapper.batchSave(any(List.class))).thenReturn(failedBatchList);
Object someResult = yourFunctionTestCall();
// THEN
verify(someResult)...

Cannot create a generic array in Java

I try to create a generic array but I'm taking the error of the title.
ByteConverter<Product> byteconverter = new ByteConverter<Product>();
//into an inner class I have to declare a final field
final ByteConverter<Product>[] byteconverter2 = {byteconverter};
So, I searched at the Stackoverflow for a possible solution. I found something similar here: Cannot create an array of LinkedLists in Java...? , so I canged my code to the following:
final ByteConverter<Product>[] byteconverter2 = {(ByteConverter<Product>[])byteconverter};
but I still take the same error. I can't understand why..Any help please?
final ByteConverter<Product>[] byteconverter2 =
new ByteConverter[]
{
byteconverter
};
this works well
This compiles, though with a warning
ByteConverter<Product> byteconverter = new ByteConverter<Product>();
ByteConverter<Product>[] byteconverter2 = new ByteConverter[] { byteconverter };
Read here http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html about restrictions for generics

Categories