How to read the tree structure from file using Java - java

I'm trying to read from a .txt file a tree structure like that:
parent Type short description1
.firstChild Type short description2
.firstNephew Type short description3
.secondChild Type short description4
.firstNephew Type short description5
.secondNephew Type short description6
parent.firstChild = value1
parent.firstChild.firstNephew = value2
parent.secondChild = value3
parent.secondChild.firstNephew = value4
parent.secondChild.secondNephew = value5
And I want the output to be a list with Test objects like that (the expected output):
[parent, type, value1, short description1,
firstChild, type, value2, short description2,
firstNephew, type, value3, short description3,
secondChild, type, value4, short description4,
firstNephew, type, value5, short description5,
secondNephew, type, value6, short description6]
So far I have:
public class Test {
private String name;
private String type;
private String value;
private String description;
public Test(String name, String type, String value, String description) {
super();
this.name = name;
this.type = type;
this.value = value;
this.description = description;
}
#Override
public String toString() {
return "name: " + name + ", type: " + type + ", value: " + value + ", description: " + description;
}
}
public class Main {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("files/file.txt")).filter(line -> !line.isEmpty())) {
List<Test> myObjectsList = lines.map(line -> {
String[] arr = line.trim().split(" +", 3);
return new Test(arr[0], arr[1], null, arr[2]);
}).collect(Collectors.toList());
myObjectsList.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

Java8 Collecting data from 2 different object streams to a sorted list of 3rd object

So here's the problem. I have three classes as below:
class ObjectClassA
{
private final long id;
private final String name;
private final boolean isReadOnly;
//<some more fields>
long getId()
{
return this.id;
}
String getName()
{
return this.name;
}
boolean isReadOnly()
{
return this.isReadOnly;
}
}
class ObjectClassB
{
private final long id;
private final String location;
private final boolean isReadOnly;
//<some more fields>
long getId()
{
return this.id;
}
String getLocation()
{
return this.location;
}
boolean isReadOnly()
{
return this.isReadOnly;
}
}
and
class ObjectClassC
{
private final String location;
private final boolean isReadOnly;
private final String location;
String getName()
{
return this.name;
}
boolean isReadOnly()
{
return this.isReadOnly;
}
String getLocation()
{
return this.location;
}
}
I have 2 maps -
Map<Id,ObjectClassA> mapObjectClassA
and
Map<Id,ObjectClassB> mapObjectClassB
Both these maps are of the same size. The Id keys are common to both maps. The aim is to iterate over either maps to create a sorted (by ObjectClassC.name) List<ObjectClassC> objects such that:
ObjectClassC.name = ObjectClassA.name
ObjectClassC.isReadOnly = ObjectClassA.isReadOnly || ObjectClassB.isReadOnly
ObjectClassC.location = ObjectClassB.location
This is the logic that I have right now is as follows:
final List<ObjectClassC> list =
mapObjectClassA.values()
.stream()
.map(a -> {
new ObjectClassC(a.getName(),
a.isReadOnly() || mapObjectClassB.get(a.getId).isReadOnly(),
mapObjectClassB.get(a.getId).getLocation())
})
.sorted(Comparator.comparing(ObjectClassC::getName))
.collect(Collectors.<ObjectClassC> toList());
My mapping and collection are working fine, but I don't get a sorted collection of ObjectClassC objects. Could someone please point out where I'm going wrong?
Not so nice, but works.
public class MapMerge_38837365 {
public static void main(String[] args) {
Map<Integer, A> as = new HashMap();
as.put(1, new A("Anna"));
as.put(2, new A("Maria"));
as.put(3, new A("Eva"));
Map<Integer, B> bs = new HashMap();
bs.put(1, new B("Adam"));
bs.put(2, new B("Edward"));
bs.put(3, new B("Jon"));
Stream.concat(
as.entrySet().stream(),
bs.entrySet().stream()
).collect(Collectors.groupingBy(Map.Entry::getKey))
.entrySet().stream()
.map(e -> e.getValue())
.map(e -> {
if (e.get(0).getValue() instanceof A)
return new AB((A) e.get(0).getValue(), (B) e.get(1).getValue());
return new AB((A) e.get(1).getValue(), (B) e.get(0).getValue());
})
.map(ab -> new C(ab.a.name+" " +ab.b.name))
.forEach(System.out::println);
}
}
"The high magic" happens in Stream.concat then groupingBy. In this two lines we create stream of all entries from both maps. Then we group them by key to map. Elements with the same key (id) will go to one List<Object>. Next step is create new stream from grouping map entrySet().stream().
Then we extract value - entries with the same Id > map(e -> e.getValue()).
Next step is to build AB objects and could be omitted but I want to extract type check and cast to another function. Now we have pseudo pair AB, that is very nice candidate for create C class map(ab -> new C(ab.a.name+" " +ab.b.name)).
Classes A, B, C and AB:
class A {
final String name;
A(String name) {
this.name = name;
}
#Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
'}';
}
}
class B {
final String name;
B(String name) {
this.name = name;
}
#Override
public String toString() {
return "B{" +
"name='" + name + '\'' +
'}';
}
}
class C {
final String name;
C(String name) {
this.name = name;
}
#Override
public String toString() {
return "C{" +
"name='" + name + '\'' +
'}';
}
}
class AB {
final A a;
final B b;
AB(A a, B b) {
this.a = a;
this.b = b;
}
#Override
public String toString() {
return "AB{" +
"a=" + a +
", b=" + b +
'}';
}
}

jackson java Unrecognized field not marked as ignorable

The error code :
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "id" (Class JacksonTester$Student), not
marked as ignorable
at [Source: [B#40334c25; line: 2, column: 8]
(through reference chain: Student["id"])
I have the below JSON file:
{
"id": "0",
"title": "0",
"externalId": "0",
"externalLink": "0",
"sourceApplication": "0",
"content": "0",
"summaryContent": "0",
"publishedDate": "0",
"harvestDate": "0",
"languageId": "0",
"regionId": "0",
"postStatus": "0"
}
and my code is
JacksonTester.java:
public class JacksonTester {
public static void main(String args[]) {
ObjectMapper mapper = new ObjectMapper();
// map json to student
try {
byte[] jsonData = Files.readAllBytes(Paths.get("output_json.txt"));
Student student = mapper.readValue(jsonData, Student.class);
System.out.println(student);
} catch (Exception e) {
e.printStackTrace();
}
}
static class Student {
String id;
String title;
String externalId;
String externalLink;
String sourceApplication;
String content;
String summaryContent;
String publishedDate;
String harvestDate;
String languageId;
String regionId;
String postStatus;
public Student() {
}
}
}
You need to either have setters for those fields or a constructor that accepts those fields as parameters (+ approriate annotations or -parameters from Java 8 and jackson-module-parameter-names
module):
public static class Student {
...
String postStatus;
public setPostStatus(postStatus) {
this.postStatus = postStatus;
}
...
}
Jackson has no access to the fields of Student.
Implement the public getters and setters for Student and it works.
I sorted this problem and it's working fine. Here is my code for the same.
**MainClass.java:**
public class MainClass {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String jsonStr = "{\r\n" + " \"id\": \"168\",\r\n" + " \"title\": \"Mr\",\r\n"
+ " \"externalId\": \"247518\",\r\n" + " \"externalLink\": \"www.gmail.com\",\r\n"
+ " \"sourceApplication\": \"adsense\",\r\n" + " \"content\": \"hmtl\",\r\n"
+ " \"summaryContent\": \"null\",\r\n" + " \"publishedDate\": \"12122018\",\r\n"
+ " \"harvestDate\": \"12122018\",\r\n" + " \"languageId\": \"3\",\r\n" + " \"regionId\": \"45\",\r\n"
+ " \"postStatus\": \"1\"\r\n" + "}";
ObjectMapper mapper = new ObjectMapper();
MyPojo details = mapper.readValue(jsonStr, MyPojo.class);
System.out.println("Value for getId is: " + details.getId());
System.out.println("Value for getSourceApplication is: " + details.getSourceApplication());
System.out.println("Value for getExternalId is: " + details.getPublishedDate());
System.out.println("Value for getExternalLink is: " + details.getExternalLink());
} }
**MyPojo.class**
public class MyPojo {
private String content;
private String id;
private String sourceApplication;
private String title;
private String postStatus;
private String publishedDate;
private String summaryContent;
private String harvestDate;
private String languageId;
private String externalId;
private String regionId;
private String externalLink;
public String getContent() {
return content;
}
public String getId() {
return id;
}
public String getSourceApplication() {
return sourceApplication;
}
public String getTitle() {
return title;
}
public String getPostStatus() {
return postStatus;
}
public String getPublishedDate() {
return publishedDate;
}
public String getSummaryContent() {
return summaryContent;
}
public String getHarvestDate() {
return harvestDate;
}
public String getLanguageId() {
return languageId;
}
public String getExternalId() {
return externalId;
}
public String getRegionId() {
return regionId;
}
public String getExternalLink() {
return externalLink;
} }
**RESULT:**
Value for getId is: 168
Value for getSourceApplication is: adsense
Value for getExternalId is: 12122018
Value for getExternalLink is: www.gmail.com
NOTE
One has to change the fields in the json to begin with a lower case letter. The reason for the JSON change is that the Jackson bean serialisation will reflect over the class, and when it sees getXyz() and setXyz() methods will map these to a Json filed names "xyz" (and not "Xyz").I think there are several ways to override this behaviour, one is to use the one of the Jackson annotations.
Instead of creating so many public getters, you could simply modify private variables to public

chars that can never be typed by keyboard in java

Currently I am using java to create an app and in that app i am trying to add a code that manually serializes a class to a string and save it into a file
For example there is this class
public class dog{
int age;
int type;
String name;
}
And I chose to manually make this class into a string using this function, results in something that resembles an xml but just something that i made up.
public String classToString(dog d){
String resultString = "" ;
resultString + "#" ;
resultString + d.age;
resultString + "#" ;
resultString + d.type;
resultString + "#" ;
resultString + d.name;
resultString + "#" ;
return resultString;
}
sp this function will return some sort of a string like
#7#4#Rex#
then when i read the file i will distinguish the different data by using # as some sort of a marking that separates different data,
what i am wondering is this,
Is this a good practice? I don't need to conceal the data from people who will open the file directly from a text viewer, so I think this would be okay. But is it efficient? are there better ways?
The biggest problem I am facing is that what if a the string that should be stored includes the special character that I have chosen which is ('#')?
To solve this problem I am wondering if there is a special preserved character that can't be written with keyboards or other user interfaces so I'd never have to save a string that includes that character
I am also thinking of making every 5th character empty so then I only write data on 4 spaces and make every 5th space empty so I can use it for special markings. for example if the age is 7 and type is 10 and the name of the dog is "abcdefghijklmnopqrstuvwxyz" the result string would be
#0007#0010#abcd^efgh^ijkl^.........^yz <
'#' is a data separator
^ is just a character that means data shouldn't be separated at this point
< means that if there are blank space characters on the left of this marking, they shouldn't be considered as part of the data and should be cut off
Create an interface called Stateful, for example. Any class implementing this interface will be responsible for loading and saving.
DogTest.java
public class DogTest {
public static void main(String[] args) {
Dog dogA = new Dog(7, 10, "abcdefghijklmnopqrstuvwxyz");
String state = dogA.save();
System.out.println(state); // #0007#0010#abcd^efgh^ijkl^mnop^qrst^uvwx^yz#
Dog dogB = new Dog().load(state);
System.out.println(dogB); // Dog [age=7, type=10, name=abcdefghijklmnopqrstuvwxyz]
}
}
Stateful.java
public interface Stateful<T> {
static final String DATA_SEP = "#";
static final String SEGMENT_SEP = "^";
T load(String data);
String save();
}
Dog.java
public class Dog implements Stateful<Dog> {
private int age;
private int type;
private String name;
public Dog() {
this(0, 0, "");
}
public Dog(int age, int type, String name) {
super();
this.age = age;
this.type = type;
this.name = name;
}
#Override
public String toString() {
return "Dog [age=" + age + ", type=" + type + ", name=" + name + "]";
}
#Override
public Dog load(String data) {
String[] fragments = StatefulUtil.parse(data);
this.age = Integer.parseInt(fragments[1], 10);
this.type = Integer.parseInt(fragments[2], 10);
this.name = StatefulUtil.decode(fragments[3]);
return this;
}
#Override
public String save() {
StringBuffer buff = new StringBuffer(Stateful.DATA_SEP);
buff.append(StatefulUtil.format(this.age)).append(Stateful.DATA_SEP);
buff.append(StatefulUtil.format(this.type)).append(Stateful.DATA_SEP);
buff.append(StatefulUtil.encode(this.name)).append(Stateful.DATA_SEP);
return buff.toString();
}
}
StatefulUtil.java
public class StatefulUtil {
public static CharSequence encode(String value) {
return separate(escape(value), Stateful.SEGMENT_SEP, 4);
}
public static String decode(String value) {
return join(value.split("\\" + Stateful.SEGMENT_SEP), "").toString();
}
private static String escape(String value) {
return value.replace(Stateful.DATA_SEP, "\\" + Stateful.DATA_SEP);
}
public static CharSequence format(int value) {
return String.format("%04d", value);
}
public static CharSequence separate(String value, String separator, int offset) {
StringBuffer buff = new StringBuffer(value);
int n = buff.length() / offset;
for (int i = 0; i < n; i++) {
int index = i + ((i + 1) * offset);
buff.insert(index, separator);
}
return buff;
}
public static CharSequence join(String[] arr, String separator) {
StringBuffer buff = new StringBuffer();
if (arr != null) {
if (arr.length > 0) {
buff.append(arr[0]);
}
for (int i = 1; i < arr.length; i++) {
buff.append(separator).append(arr[i]);
}
}
return buff;
}
// Regular expression: /^#|[^\\\\]#/ - Match beginning '#' and each non-escaped '#"
public static String[] parse(String data) {
return data.split("^" + Stateful.DATA_SEP + "|[^\\\\]" + Stateful.DATA_SEP);
}
}
Just use a Stateful or a Serializable class. Here's an example of a serializable class:
public class Dog implements Serializable {
...
}
Then you can use an ObjectOutputStream and ObjectInputStream to write and read the object respectively.
ObjectOutputStream out = new ObjectOutputStream( yourFileStream );
out.writeObject(yourDogObject);
That will write the yourDogObject out to yourFileStream.
As such an application may grow, and data change, my preference would be for XML, using JAXB with annotations. At least some human readable text, maybe versioned.
Dog dog = load(Dog.class, "dog.xml");
The loading/saving code is something like:
public <T> T load(Class<T> type, String path) {
JAXBContext jc = JAXBContext.newInstance();
Unmarshaller u = jc.createUnmarshaller();
return type.cast(u.unmarshal(new FileInputStream(path));
}
public <T> void save(T obj, String path) {
JAXBContext jc = JAXBContext.newInstance();
Marshaller m = jc.createMarshaller();
m.unmarshal(obj, new FileOutputStream(path));
}
And with annotations you may control the XML:
#XmlRootElement(name="dog")
public class Dog implements Stateful<Dog> {
#XmlAttribute(name = "vs")
private String dataVersion = "1.0";
#XmlAttribute(name = "age")
private int age;
#XmlAttribute
private int type;
#XmlElement(name = "name")
private String name;
}
for
<dog vs="1.0" age="6" type="3">
<name>Cerberus</name>
</dog>
One can have lists etcetera.

Java string sorting

This is no homework.Its an exercise I came across in a book.
Build a class named Name which represents the name of a person.The class should have fields that represent first name ,last name ,and fathersname.
The class should have these methods :
public Name (String fn,String f_n,String ln)
/* initializes the fields of an object with the values fn,f_n and m.
fn means first name
ln means last name
f_n means fathersname btw. */
public String getNormalOrder(); //returns the name of the person in the normal order : first name,fathers name,last name.
public String getReverseOrder(); //returns the name of the person in the reverse order : last name,fathers name,first name.
public boolean compare (String fn,String f_n,String ln); // Returns true if the first name is the same with fn,fathers name is the same with f_n, last name with ln.If the opposite happens it returns false.
Build a program named TestName which tests the methods of the class Firstname.
My solution
public class Name {
String fn;
String f_n;
String ln;
public Name(String initialfn, String initialf_n, String initialln) {
fn = initialfn;
f_n = initialf_n;
ln = initialln;
}
public String getNormalOrder() {
return fn + " " + f_n +
" " + ln;
}
public String getReverseOrder() {
return ln + ", " + f_n +
" " + fn + " ";
}
}
How about the third method which is comparing? Also how do I test the class?
For a flexible solution:
public enum NameMember {
FIRSTNAME, SECONDNAME, FATHERSNAME;
}
The Name class:
public class Name {
private final String firstName;
private final String secondName;
private final String fathersName;
public Name(String firstName, String secondName, String fathersName) {
this.firstName = firstName;
this.secondName = secondName;
this.fathersName = fathersName;
}
public String getName(NameMember member1, NameMember member2, NameMember member3) {
StringBuilder sb = new StringBuilder();
return sb.append(getMember(member1)).append(" ")
.append(getMember(member2)).append(" ")
.append(getMember(member3)).toString();
}
public String getMember(NameMember member) {
switch (member) {
case FIRSTNAME:
return firstName;
case SECONDNAME:
return secondName;
case FATHERSNAME:
return fathersName;
default:
return null;
}
}
#Override
public String toString() {
return getName(NameMember.FIRSTNAME, NameMember.SECONDNAME, NameMember.FATHERSNAME);
}
}
A NameComparator (flexible) class:
import java.util.Comparator;
public class NameComparator implements Comparator<Name> {
private NameMember nameMember;
public NameComparator(NameMember nameMember) {
this.nameMember = nameMember;
}
#Override
public int compare(Name name1, Name name2) {
return name1.getMember(nameMember).compareTo(name2.getMember(nameMember));
}
}
And the main class (test drive):
public static void main(String args[]) {
List<Name> names = new ArrayList<>();
names.add(new Name("Alice", "Burda", "Christophe"));
names.add(new Name("Ben", "Ashton", "Caine"));
names.add(new Name("Chane", "Bagwell", "Alex"));
names.add(new Name("Ann", "Clinton", "Brad"));
System.out.println("NAMES ORDERED BY FIRST NAME:");
Collections.sort(names, new NameComparator(NameMember.FIRSTNAME));
printNames(names);
System.out.println("\nNAMES ORDERED BY SECOND NAME:");
Collections.sort(names, new NameComparator(NameMember.SECONDNAME));
printNames(names);
System.out.println("\nNAMES ORDERED BY FATHERSNAME:");
Collections.sort(names, new NameComparator(NameMember.FATHERSNAME));
printNames(names);
}
private static void printNames(Collection<Name> names) {
names.stream().forEach(System.out::println);
}

Auto generate id

I'm trying to auto generate an id for customers,
and all i get is 0 every time.
Pretty sure the problem is in public void regCustomer().
public class User {
private String firstName, gender, age;
String surename;
private int customerID;
private static int idCounter = 1000;
User next;
public User(String fN, String sn, String g, String a) {
firstName = fN;
surename = sn;
gender = g;
age = a;
//customerID = cID;
next = null;
}
public void setCustomerID() {
customerID = idCounter++;
}
public int getCustomerID() {
return customerID;
}
public String toString() {
return customerID + "\t" + surename + "\t" + firstName + "\t" + age
+ "\t" + gender;
}
}
In the Window class
public void regCustomer() {
//int customerID = 0;//= Integer.parseInt(customerIDField.getText());
String firstName = firstNameField.getText();
String surename = surenameField.getText();
String gender = genderField.getText();
String age = ageField.getText();
if (!firstName.equals("") && !surename.equals("") && !gender.equals("")&& !age.equals("")) {
userA.regCustomer(new User(firstName, surename, gender,age));
User u = new User(firstName, surename, gender,age);
u.getCustomerID();
customerIDField.setText("");
firstNameField.setText("");
surenameField.setText("");
ageField.setText("");
genderField.setText("");
firstNameField.requestFocus();
} else
JOptionPane.showMessageDialog(this, "Alle felt må fylles inn");
}
You never set the ID and that is why it is zero.
You can use a private static final AtomicInteger to generate your id sequence; simply read from it in your constructor:
private static AtomicInteger ID_GENERATOR = new AtomicInteger(1000);
public User(String fN, String sn, String g, String a) {
customerID = ID_GENERATOR.getAndIncrement();
//rest of constructor
}
You should use an AtmoicInteger as this is thread safe and the getAndIncrement method is atomic. There are not such guarantees for an int.
The question that needs to answered is whether these items are persisted in any way, and if so what happens then - id generation will always start from 1000 using this technique.
Move customerID = idCounter++; to the constructor.

Categories