quick question about creating objects when given a Class object. Or maybe I need to go about this differently. First off my plan, I am writing a method that will take an array of File objects, and read each one into a Set, where each set is then appended to a list and the list returned. Below is what I have:
private static List<Set<String>> loadFiles(File[] files, Class whatType, Charset charSet){
List<Set<String>> setList = new ArrayList<Set<String>>(files.length);
try {
for(File f : files){
BufferedInputStream bs = new BufferedInputStream(new FileInputStream(f));
InputStreamReader r = new InputStreamReader(bs, charSet);
BufferedReader br = new BufferedReader(r);
Set<String> set = new HashSet<>(); //This is the problem line
String line = null;
while( (line = br.readLine()) != null){
set.add(line.trim());
}
br.close();
setList.add(set);
}
return setList;
} catch (FileNotFoundException e) {
//Just return the empty setlist
return setList;
} catch (IOException e) {
//return a new empty list
return new ArrayList<Set<String>>();
}
}
But what I want is to allow the user of the method to specify the type of Set to instantiate (as long as it contains Strings of course). That is what the 'whatType' param is for.
All my research has lead me to how to instantiate an object given the class name, but that is not really what I am after here.
If you can use Java8, you can solve this problem easily. Declare the method as follows:
private static List<Set<String>> loadFiles(File[] files, Supplier<Set> setSupplier, Charset charSet)
Change your problem line to:
Set<String> set = setSupplier.get();
Then, in each call to this method, the setSupplier param can be easily provided using method references: HashSet::new, TreeSet::new...
How about using Class.newInstance() method? I coded a simple example for you:
public <T extends Set> void myMethod(Class<T> type) {
T object;
try {
object = type.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public void caller() {
myMethod(HashSet.class);
}
Is this what you are looking for?
If you assume the class has a no-argument accessible constructor, you're basically a newInstance() call away:
Set<String> set = (Set<String) whatType.newInstance();
Note that if you define whatType as a Class<? extends Set> instead of just a raw Class, you can get rid of this ugly cast too.
Related
I have a class A as
Class A{
private static final String ANON_DIR = "/webapps/worldlingo/data/anonymizer/";
private static final String NO_ANON = "noanonymize";
public String first(String text, String srclang, Map dictTokens) {
Set<String> noAnonymize = new HashSet<String>();
second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");
String value;
if(noAnonymize.contains("test")){
value = "test1";
}
else {
value = "test";
}
return value;
}
where ANON_DIR and NO_ANON is static final value. This class has function first and function second .The first function has a calling method in it which calls second function. The second function is void function which takes static fields as parameter.
Second function is just the file read function with the path provided as
public void second (Set<String> hashSet, String path, String lang , String type) {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(path);
br = new BufferedReader(fr);
String Line;
while ((Line = br.readLine()) != null) {
hashSet.add(Line);
}
} catch (IOException e) {
log.error("Anonymizer: Unable to load file.", e);
} finally {
try {
if (fr != null) {
fr.close();
}
if (br != null) {
br.close();
}
} catch (IOException e) {
log.error("Anonymizer : An error occured while closing a resource.", e);
}
}
}
}
Now I am trying to test the function first using mockito. I am trying update the passed first argument (list parameter) i.e noAnonymize in second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");
public void testfirst() throws Exception {
Anonymizer mock = PowerMockito.mock(Anonymizer.class);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
List<String> args = invocation.getArgumentAt(0,List.class);
args.add("a");
args.add("b");
return null; // void method, so return null
}
}).when(mock).readNoAnonymizeFile(Mockito.anySet(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString());
Method anonymizeNames = anon.getClass().getDeclaredMethod("anonymizeNames_test", String.class, String.class, Map.class);
String srcLang = "MSFT_EN";
Map mapTokens = new HashMap();
String result = (String) anonymizeNames.invoke(anon,"I am David",srcLang,mapTokens);
}
PROBLEM:
I am not able to mock the void second method to update list with value a and b. How can I have the mockto test case to update parameter in void method.
When unit testing a class, you test it through its public methods. If you can't test the class sufficiently through its public methods, it needs re-factored.
In this case, you're trying to unit test a private method for an edge case that doesn't exist. Why even provide the constant as a parameter? Why not reference it directly in the private method and save passing an argument? Instead, you could write:
fr = new FileReader(ANON_DIR + NO_ANON);
EDIT
After Laxmi and I had a discussion we came up with a solution using constructor based dependency injection and changing the void method to return Set<String>. This let us test in isolation and mock easily.
I am trying to know the best possible way to sort a file.txt lines in a Java collection.
Using orderedSet removes duplication and I don't want that.
PriorityQueue does the job but I need my class to be Iterable and using PriorityQueue.Iterator does not give sorted results.
Now I am confused with using Arrays.sort or going with this approach:
using PriorityQueue when reading lines from text then copying the final Queue on an array to use its Iterator?
public class FileSorter implements Iterable<String> {
// this sorted set contains the lines
private PriorityQueue<String> lines0 = new PriorityQueue<>() ;
private ArrayList<String> lines = new ArrayList<>();
public void readFiles (String[] filePaths) throws IOException {
BufferedReader buf = null;
String line ;
for (String path:filePaths) {
//opening the file
buf = new BufferedReader(new FileReader(new File(path)));
//iterating through the lines and adding them the collection
while ((line = buf.readLine()) != null) {
if(line.trim().length() > 0) { //no blank lines
lines0.add(line);
}
}
};
//closing the buffer
buf.close();
while (!lines0.isEmpty()){
lines.add(lines0.poll());
}
}
public Iterator<String> iterator() {
return lines.iterator();
}
}
Thank you.
I think implementing Iterable is not the best approach because you should prefer composition over inheritance, and it's 2017 after all; no one implements their own collection classes anymore. That said, how about the following?
public class Main {
public static void main(String[] args) throws IOException, URISyntaxException {
for (String line : new FileSorter(new File(Main.class.getResource("test.txt").toURI()).toPath())) {
System.out.println(line);
}
}
static class FileSorter implements Iterable<String> {
private final Path path;
FileSorter(Path path) {
this.path = path;
}
#Override
public Iterator<String> iterator() {
try {
return Files.lines(path)
.sorted()
.iterator();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
}
Given a file test.txt in the same dir as the class Main:
a
b
a
c
The above program prints:
a
a
b
c
Iterable has different semantic than Stream because the former can be reused, while the latter can only be used once (until a terminal operation). Thus, my implementation reads the file every time you call iterator(). I didn't attempt to optimize it because you didn't ask for it, and premature optimization is the root of all evil.
I know the title doesn't say much, but I have a pretty specific problem that is difficult to describe:
I'm making an android app with Android Studio, and for one activity I have a list where the values that are stored in a json file will go.
For getting these values I use another class with a get() method which returns the values in an arraylist. The problem is that the IDE says 2 contrary statements: in the activity class it says that the get() method has to be static and in the other class it says that the get() method can't be static.
This is the code:
CompanySelector.java (the activity)
public class CompanySelector extends AppCompatActivity {
ArrayList<String> companyList = CompanyStorage.get();
}
==> here it gives an error in CompanyStorage.get() and says that get() should be static.
CompanyStorage.java (the other class)
abstract class CompanyStorage extends Context {
private ArrayList<String> companyList;
protected CompanyStorage() throws JSONException {
companyList = get();
}
ArrayList<String> get() throws JSONException {
JSONObject companyData = new JSONObject();
ArrayList<String> companyList = new ArrayList<>();
// Open data.json and convert to JSONObject
String json = OpenFileAsString("data.json");
try {
companyData = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
}
// return json array as ArrayList
if (companyData.getJSONArray("companies") != null) {
for (int i=0;i<companyData.getJSONArray("companies").length();i++){
companyList.add(companyData.getJSONArray("companies").getString(i));
}
}
return companyList;
}
public String OpenFileAsString(String filename) {
try {
InputStream stream = getAssets().open( filename );
int size = stream.available();
byte[] bytes = new byte[size];
stream.read(bytes);
stream.close();
return new String( bytes );
} catch ( IOException e ) {
Log.i("GuiFormData", "IOException: " + e.getMessage() );
}
return null;
}
}
==> Here it says that if get() is static, OpenFileAsString() should also be static, but then it gives an error, because getAssets() can't be in a static method.
Does anyone know what I should do? I'm fairly new to Java and application design..
Try to put static at the get() and OpenFileAsString(String filename) methods header and use context.getAssets() instead of getAssets()
Ok so i have two classes: Content and TrackUserChanges . They have the same fields.
public class Content{
private Long id;
......
private SortedSet<Content> children = new TreeSet<Content>();
}
public class TrackUserChanges{
private Long id;
.....
private SortedSet<Content> children = new TreeSet<Content>();
}
I want to clone the data from Content to TrackUserChanges:
I have the children from an instance of content:
SortedSet<Content> children = content.getChildren();
This can contain many other contents, and that contents can have also children, etc.
SortedSet<TrackUserChanges> children1 = convertContentSetToTrackUserChangesSet(children);
This is the method:
public SortedSet<TrackUserChanges> convertContentSetToTrackUserChangesSet(SortedSet<Content> children){
SortedSet<TrackUserChanges> children1 = new TreeSet<TrackUserChanges>();
for(Content c : children){
TrackUserChanges trackU = new TrackUserChanges();
trackU.setCategory(c.getCategory());
trackU.setId(c.getId());
trackU.setBook(c.getBook());
trackU.setInsertUser(c.getInsertUser());
trackU.setParent(c.getParent());
trackU.setParentId(c.getParentId());
trackU.setRelativeSortOrder(c.getRelativeSortOrder());
trackU.setText(c.getText());
trackU.setType(c.getType());
children1.add(trackU);
}
return children1;
}
I need somehow to call recusively or something like that... and I can't do trackU.setChildren(c.getChildren()) because the types don't match :/
#Mifmif
try {
FileOutputStream fout = new FileOutputStream("a.dat");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(content);
oos.close();
}
catch (Exception e) { e.printStackTrace(); }
TrackUserChanges trackUserChanges11 = new TrackUserChanges();
try {
FileInputStream fin = new FileInputStream("a.dat");
MyCustomObjectInputStream custom = new MyCustomObjectInputStream(fin);
// custom.readClassDescriptor();
trackUserChanges11 = (TrackUserChanges) custom.readObject();
System.out.println("IDDDDD" + trackUserChanges11.getId());
custom.close();
}
catch (Exception e) { e.printStackTrace(); }
ClassCastException :)
If you have two classes with identical properties that have identical behaviour, separate those fields/behaviour into a separate class and extend that class in your other classes. This should allow you to copy directly between them.
Make your class implements Cloneable. Then just call the function clone of the SortedSet.
http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html
Here is a solution based on serialization , make both of your class serializable and if you want to go from one class instance to another, serialize your instance into a file , and read it using MyCustomObjectInputStream :
class MyCustomObjectInputStream extends ObjectInputStream {
public MyCustomObjectInputStream(InputStream in) throws IOException {
super(in);
}
#Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
if (resultClassDescriptor.getName().equals("name.of.the.package.OldClassName"))
resultClassDescriptor = ObjectStreamClass.lookup(name.of.the.package.NewClassName.class);
return resultClassDescriptor;
}
}
I resolved the problem
public TrackUserChanges convertContentToTrack(Content c) {
TrackUserChanges t = new TrackUserChanges();
t.setCategory(c.getCategory());
t.setId(c.getId());
t.setBook(c.getBook());
t.setInsertUser(c.getInsertUser());
t.setParent(c.getParent());
t.setParentId(c.getParentId());
t.setRelativeSortOrder(c.getRelativeSortOrder());
t.setText(c.getText());
t.setType(c.getType());
if (c.getChildren().size() == 0) {
return t;
}
SortedSet<TrackUserChanges> childs = new TreeSet<TrackUserChanges>();
for (Content content : c.getChildren()) {
childs.add(convertContentToTrack(content));
}
t.setChildren(childs);
return t;
}
Thanks anyway :)
I have a Java class MyPojo that I am interested in deserializing from JSON. I have configured a special MixIn class, MyPojoDeMixIn, to assist me with the deserialization. MyPojo has only int and String instance variables combined with proper getters and setters. MyPojoDeMixIn looks something like this:
public abstract class MyPojoDeMixIn {
MyPojoDeMixIn(
#JsonProperty("JsonName1") int prop1,
#JsonProperty("JsonName2") int prop2,
#JsonProperty("JsonName3") String prop3) {}
}
In my test client I do the following, but of course it does not work at compile time because there is a JsonMappingException related to a type mismatch.
ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }
I am aware that I could alleviate this issue by creating a "Response" object that has only an ArrayList<MyPojo> in it, but then I would have to create these somewhat useless objects for every single type I want to return.
I also looked online at JacksonInFiveMinutes but had a terrible time understanding the stuff about Map<A,B> and how it relates to my issue. If you cannot tell, I'm entirely new to Java and come from an Obj-C background. They specifically mention:
In addition to binding to POJOs and "simple" types, there is one
additional variant: that of binding to generic (typed) containers.
This case requires special handling due to so-called Type Erasure
(used by Java to implement generics in somewhat backwards compatible
way), which prevents you from using something like
Collection.class (which does not compile).
So if you want to bind data into a Map you will need to use:
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });
How can I deserialize directly to ArrayList?
You can deserialize directly to a list by using the TypeReference wrapper. An example method:
public static <T> T fromJSON(final TypeReference<T> type,
final String jsonPacket) {
T data = null;
try {
data = new ObjectMapper().readValue(jsonPacket, type);
} catch (Exception e) {
// Handle the problem
}
return data;
}
And is used thus:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
TypeReference Javadoc
Another way is to use an array as a type, e.g.:
ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);
This way you avoid all the hassle with the Type object, and if you really need a list you can always convert the array to a list by:
List<MyPojo> pojoList = Arrays.asList(pojos);
IMHO this is much more readable.
And to make it be an actual list (that can be modified, see limitations of Arrays.asList()) then just do the following:
List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
This variant looks more simple and elegant.
//import com.fasterxml.jackson.core.JsonProcessingException;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.fasterxml.jackson.databind.type.CollectionType;
//import com.fasterxml.jackson.databind.type.TypeFactory;
//import java.util.List;
CollectionType typeReference =
TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);
This works for me.
#Test
public void cloneTest() {
List<Part> parts = new ArrayList<Part>();
Part part1 = new Part(1);
parts.add(part1);
Part part2 = new Part(2);
parts.add(part2);
try {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(parts);
List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
} catch (Exception e) {
//fail("failed.");
e.printStackTrace();
}
//TODO: Assert: compare both list values.
}
I am also having the same problem. I have a json which is to be converted to ArrayList.
Account looks like this.
Account{
Person p ;
Related r ;
}
Person{
String Name ;
Address a ;
}
All of the above classes have been annotated properly.
I have tried TypeReference>() {}
but is not working.
It gives me Arraylist but ArrayList has a linkedHashMap which contains some more linked hashmaps containing final values.
My code is as Follows:
public T unmarshal(String responseXML,String c)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
try
{
this.targetclass = (T) mapper.readValue(responseXML, new TypeReference<ArrayList<T>>() {});
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return this.targetclass;
}
I finally solved the problem. I am able to convert the List in Json String directly to ArrayList as follows:
JsonMarshallerUnmarshaller<T>{
T targetClass ;
public ArrayList<T> unmarshal(String jsonString)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
JavaType type = mapper.getTypeFactory().
constructCollectionType(ArrayList.class, targetclass.getClass()) ;
try
{
Class c1 = this.targetclass.getClass() ;
Class c2 = this.targetclass1.getClass() ;
ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString, type);
return temp ;
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null ;
}
}