Java converting from Object to Subclass - java

Here is my code for Scene.java. It has different types of objects, all of which are included in one common ArrayList called targets. All of them share a toString() method that returns their identifier. I want to use the targets list to determine if there is any object in the scene that matches a given identifier, regardless of its type:
ArrayList<NPC> npcs = new ArrayList<NPC>();
ArrayList<Item> items = new ArrayList<Item>();
ArrayList<EnviromentalObject> enviromental_objects = new ArrayList<EnviromentalObject>();
ArrayList<Object> targets;
public Object check_for_target(String target_name){
targets.addAll(npcs);
targets.addAll(items);
targets.addAll(enviromental_objects);
for (Object target : targets){
if (target.toString() == target_name){
return target;
}
}
return null;
Here is the code in Game.java, which checks for a given identifier. If there is a match ion the current scene, I want to know the object's type and treat it as its true type. Right now, I have the following code, and I knew it wouldn't work, but maybe it'll help get my idea across.
Object target = current_scene.check_for_target(target_name);
if (target == null){
System.out.println(UNRECOGNIZED_TARGET_MESSAGE);
} else {
String target_type = target.getClass().getName();
target = (target_type) target;
}
What would be the correct way of getting the object's type and then being able to use that object's methods? Right now, I'm only given Object's methods. Do I create a superclass for NPC, Item, and EnviromentalObject?

Basically, you can check if an object is an instance of a specific class.
it could be something like this :
if( target instanceof NPC) {
System.out.println("target is a NPC");
}
else if( Target instanceof Item) {
System.out.println("target is an Item");
}
if( target instanceof EnviromentalObject) {
System.out.println("target is EnviromentalObject");
}
Edit: as we talked in the comments I think you can change your code to reach a better solution. The above code is still works but it can be a very good practice to using Design Patterns that are known as best practices in programming. For this situation think about using java interface and define share methods that each object could implements them by its need. In the simplest way they print their identifier. Let's use an example :
public interface SceneThings() {
public void printIdentifire();
public String doSomeOtherThings();
}
Each object can implements the above interface by it needs like :
public class Item implements SceneThing {
...
public void printIdentifire(){
//print its identifier here.
System.out.print("ID:ITEM###");
}
public String doSomeOtherThings(){
//do some other works !!!
}
...
}
for other items same as above. And then you can use a single array to keep them without worry about their origin class like this:
ArrayList<SceneThings> targets = new ...
SceneThing obj = new Item();
targets.add(obj);
I hope this can help you to define a better solution in your case.

One of the ways how it could be done it to declare a superclass or interface Target and use it to keep targets array, the full code sample with abstract class:
ArrayList<NPC> npcs = new ArrayList<NPC>();
ArrayList<Item> items = new ArrayList<Item>();
ArrayList<EnviromentalObject> enviromental_objects = new ArrayList<EnviromentalObject>();
ArrayList<Target> targets;
public Target check_for_target(String target_name) {
targets.addAll(npcs);
targets.addAll(items);
targets.addAll(enviromental_objects);
for (Target target : targets) {
if (target.toString().equals(target_name)) {
return target;
}
}
return null;
}
private abstract class Target {}
private class NPC extends Target {}
private class Item extends Target {}
private class EnviromentalObject extends Target {}

Related

avoiding if conditions for similar type of checks

Is there anyway to avoid these if conditions? because there may be different type of objects coming in.
if ("OpenOrder".equals(order.getClass().getSimpleName())) {
return OpenOrderBuilder.createOFSMessage((OpenOrder) order); //Returns String
}
if ("ExecutionOrder".equals(order.getClass().getSimpleName())) {
return ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order); //Returns String
}
You can use a Router pattern to do this. Simple add the computations in a Map like this:
Map<String, Function> router = new HashMap<>();
router.put("OpenOrder", (value) -> OpenOrderBuilder.createOFSMessage((OpenOrder) value));
router.put("ExecutionOrder", (value) -> ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order));
And you can route the order using the String key. Here is a "OpenOrder" example:
String result = (String) router.get("OpenOrder").apply(order);
There are many ways to do it. Which one to choose, depends on your needs and in this case in particular on how many different types of objects you will have.
I suggest looking at concepts like interfaces and inheritance and on specific design patterns.
One approach I tend to like, although still not perfect, works as follows:
interface Order {
}
interface OrderBuilder<T> {
T forType();
Object createOFSMessage(Order order);
}
class OpenOrderBuilder<OpenOrder> implements OrderBuilder {
#Override
OpenOrder forType() {
return OpenOrder.class;
}
...
}
class ExecutionOrderBuilder<ExecutionOrder> implements OrderBuilder {
#Override
ExecutionOrder forType() {
return ExecutionOrder.class;
}
...
}
class MyProcessor {
Map<Class, OrderBuilder> obs;
public void initialize() {
List<OrderBuilder> builders = new ArrayList<>();
builders.add(new OpenOrderBuilder());
builders.add(new ExecutionOrderBuilder());
obs = new HashMap<Class, OrderBuilder>();
for(OrderBuilder b : builders) {
obs.put(b.forType(), b);
}
}
public Object createOFSMessage(Order order) {
return obs.get(order.getClass()).createOFSMessage(order);
}
}
In the above example, adding a new implementation would just consist of adding an entry to the builders collection. While in the example above it's done manually, normally this is done through Dependency Injection and frameworks like spring (in which case, the initialize method may turn into a constructor with builders as an #Autowired argument).
There are of course other ways, some more simple some more complicated. The best way really depends on what you have to do and one key rule: the less code you have the better.
First one should not forget the switch-on-string:
switch (order.getClass().getSimpleName()) {
case "OpenOrder":
return OpenOrderBuilder.createOFSMessage((OpenOrder) order); //Returns String
case "ExecutionOrder":
return ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order); //Returns String
}
The code however shows inheritance being used in combination with static child class factories. Evidently a createOFSMessage is not desired in the Order base class.
Then use a non-static "builder" - a factory. Follow the strategy pattern.
If you already know the type when calling the method, this code can help you :
private String CreateOFSMessage(Class<T> classOrder) {
if ("OpenOrder".equals(classOrder.getSimpleName())) {
return OpenOrderBuilder.createOFSMessage((classOrder) order);
}else if ("ExecutionOrder".equals(classOrder.getSimpleName())) {
return ExecutionOrderBuilder.createOFSMessage((classOrder) order);
}
}

Is there a way to check condition while streaming a list

I have a Persons entity and it has a field contactType.
Now according to contact type I want to map List to different resource file ie WorkContactResource or HomeContactResource.I will be using java 8.
workContact=personList.stream().filter(p->p.getPhoneType == PhoneType.WORK).map(WorkResource::new).collect(Collectors.toList());
homeContact=personList.stream().filter(p->p.getPhoneType == PhoneType.HOME).map(HomeResource::new).collect(Collectors.toList());
workContact.addAll(homeContact);
I made to two different List.
But what I want is while streaming personsList I would be checking if contactType is home or work and there only map to specific resource.
How to achieve this.
I believe it should be something like this
abstract class Resource {
}
class WorkResource extends Resource {
public WorkResource(Person person) {
***********
}
}
class HomeResource extends Resource {
public HomeResource(Person person) {
***********
}
}
Map<PhoneType, List<Resource>> contacts = personList.stream().collect(Collectors.groupingBy(p->p.getPhoneType, Collectors.mapping(Resource::new)));
And then iterate through a map by the type
Given that you want a single list as an output, the most neat would be probably to create a method that does that and refer to it: .map(this::asResource)
public Resource asResource(Person person) {
if (person.getPhoneType() == PhoneType.WORK) {
return new WorkResource(person);
} else {
return new HomeResource(person);
}
}
That would make your code look like this:
personList.stream()
.map(this::asResource)
.collect(toList());
You can also declare that method in another class, as static so that the usage looks e.g. like this PersonConverter::asResource.

Initializing objects dynamically

The following code is a simplified version. The Write and Read are classes that implement the IAction interface.
IAction newAction;
if (userInput.equalsIgnoreCase("WRITE")){
newAction = new Write();
}
else if (userInput.equalsIgnoreCase("READ")){
newAction = new Read();
}
...
If I had many actions to implement then i would have to go through too many if statements. So the question is if there is a way to automatically create each class without getting through all these if statements?
I depends on what you mean by "automatically". Computers do things automatically, but not before someone programmed to do something automatically. You probably mean "less cumbersome". Here is an approach that uses Java 8 features.
// Make a Map that tells what word should be coupled to what action
Map<String, Supplier<IAction>> actionMapping = new HashMap<>();
actionMapping.put("WRITE", Write::new);
actionMapping.put("READ", Read::new);
// When you get user input, simply lookup the supplier
// in the map and call get() on it
IAction action = actionMapping.get(userInput.toUpperCase()).get();
If you're not using Java 8, you can use a slightly different (but similar) approach:
// Map that tells what word should be coupled to what action
Map<String, Class<? extends IAction>> actionMapping = new HashMap<>();
actionMapping.put("WRITE", Write.class);
actionMapping.put("READ", Read.class);
// Lookup the action class for the input and instantiate it
IAction action = actionMapping.get(userInput.toUpperCase()).newInstance();
Yes, its possible. First create an Object. Then check if the Classname exists to make sure that the userinput is a valid class, then create a dynamic class. After that assign it to your Object.
Object newAction = null;
try {
Class<?> clazz = Class.forName( "your.fqdn.class."+userInput );
Constructor<?> ctor = clazz.getConstructor(String.class);
newAction = ctor.newInstance(new Object[] { ctorArgument });
newAction = new your.fqdn.class."+userInput;
} catch( ClassNotFoundException e ) {
// catch an error if the class for the object does not exists.
}
You can later check for the class by using
if (newAction instanceOf MyClass) { }
else if (newAction instanceOf Anotherclass) {}
But be carefull. This is for security reasons not recommend. You should validate the input before you do that!
You can create an enum.
public enum Action implements IAction{
READ,WRITE;
}
And use it in one line like so.
IAction action = Action.valueOf(userInput.toUpperCase());
You can use a enum and implement the interface for each enum constant. Here's an example for implementing Consumer<String>:
public enum Action implements java.util.function.Consumer<String> {
READ {
#Override
public void accept(String t) {
System.out.println("Read: "+t);
}
},
WRITE {
#Override
public void accept(String t) {
System.out.println("Write: "+t);
}
};
}
You can use it like this:
Consumer<String> c = Action.valueOf("READ");
c.accept("Greetings!");
c = Action.valueOf("WRITE");
c.accept("Hello World!");
This will print
Read: Greetings!
Write: Hello World!
You can use String.toUpperCase() get the right constant regardless of upper and lower case.

JAVA cast Object with "unknown" type in type of another Object

Im new here and i want to start with my first not so easy to describe Questions. I think a piece of code can explain best.
public void erlaube(Geraet pGeraet){
for(Object g : mGeraetetypen){
if(pGeraet.getClass().equals(g.getClass())){
System.out.println("TRUE");
mErlaubt.add((g.getClass())pGeraet); // MY PROBLEM
}
//System.out.println(pGeraet.getClass());
//System.out.println(g.getClass());
}
}
A "Geraet" (Device) is an abstract Class and it can be a Sensor or an Actor f.ex. the class Temperaturesensor.
Geraetetypen (Devicetypes) is an ArrayList and contains all available Sensors and Actors.
The for- and if-block checks if the parameter Object is a type of an Object contained in the Devicetypes list f.ex. Temperaturesensor.
if it is, i want to add it as this datatype (Temperaturesensor) to the "mErlaubt" (mAllowed) ArrayList.
So it should do the same as This (cast):
mErlaubt.add( (Temperatursensor) pGeraet);
But i dont want to cast explicit with (Temperatursensor). I want to cast dynamic with the datatype i found from the Datatypelist that compares.
Maybe something like the line with the comment //MY PROBLEM, but this doesnt work.
I know this is hard and my description is not verry well, but i hope you understand what i try to do. Please help. If you dont understand something or have a Question please ask.. Thanks!
Referring to your code sample, I'd suggest to store the allowed classes instead of instances of the allowed classes. You could use this modified code:
public class Deviceplace {
Set<Class<? extends Geraet>> mErlaubt;
public Deviceplace(){
mErlaubt = new HashSet<>();
}
public void erlaube(Class<? extends Geraet> clazz) {
mErlaubt.add(clazz);
}
// Option 1: no subtypes of the allowed types
public boolean isErlaubt(Geraet pGeraet) {
return mErlaubt.contains(pGeraet.getClass());
}
public static void main(String[] args) {
Deviceplace place = new Deviceplace();
place.erlaube(Temperatursensor.class);
System.out.println(place.isErlaubt(new Windsensor()));
System.out.println(place.isErlaubt(new Temperatursensor()));
}
}
An alternative implementation of isErlaubt that also includes subtypes would be:
// Option 2: including subtypes of the allowed types
public boolean isErlaubt(Geraet pGeraet) {
for(Class<? extends Geraet> clazz : mErlaubt){
if (clazz.isAssignableFrom(pGeraet.getClass())) {
return true;
}
}
return false;
}
If your mErlaubt is an ArrayList of Geraet superclass, then you just have to use mErlaubt.add(pGeraet);
Your mErlaubt must then be defined like : List<Geraet> mErlaubt = new ArrayList<Geraet>();
You want to retrieve the class from a specific item of a list, and cast another object to this class? Apart from someClass.cast(someObject), there won't be any solutions. But as far as i can see, this whole code doesn't make any sense. You'll add a single object multiple times. And apart from that i'd say that's rather a job for Generics than casting.
I think that this change should work as pGeraet is of Class Geraet so casting a variable to the super class should work.
for(Object g : mGeraetetypen){
if(pGeraet.getClass().equals(g.getClass())){
System.out.println("TRUE");
mErlaubt.add((Geraet)pGeraet);
}
Thank you all! I want to share my verry simple solution to all. The class is a Deviceplace for Sensors/Actors on a houseautomation GUI. Each Deviceplace allows only a hand full of Sensor/Actors (f.ex. no Heating on a outside place)
public class Deviceplace {
ArrayList<Geraet> mErlaubt; //allowed devices
public Deviceplace(){
mErlaubt = new ArrayList<>();
}
public void erlaube(Geraet pGeraet){ //add allowed device
mErlaubt.add(pGeraet);
}
public boolean isErlaubt(Geraet pGeraet){ // check if device is allowed on this place
for(Geraet g : mErlaubt){
if(g.getClass().isInstance(pGeraet)){
return true;
}
}
return false;
}
public static void main(String[] args) {
Deviceplace place = new Deviceplace();
place.erlaube(new Temperatursensor()); // ad Temperaturesensor as allowed device
// now check if a device is allowed on this deviceplace
System.out.println(place.isErlaubt(new Windsensor())); // RETURNS false (Windsensor not allowed)
System.out.println(place.isErlaubt(new Temperatursensor())); // RETURNS true (Temperaturesensor allowed)
}
}

Jackson Change JsonIgnore Dynamically

I have a class and there are variables inside it as well. Sometimes I want to ignore some fields and sometimes not when deserializing (maybe at serializing too). How can I do it at Jackson?
For serialization, "filtering properties" blog entry should help. Deserialization side has less support, since it is more common to want to filter out stuff that is written.
One possible approach is to sub-class JacksonAnnotationIntrospector, override method(s) that introspect ignorability of methods (and/or fields) to use whatever logic you want.
It might also help if you gave an example of practical application, i.e what and why you are trying to prevent from being deserialized.
You might want to use JsonViews ( took it originally from http://wiki.fasterxml.com/JacksonJsonViews - broken now - web archive link: https://web.archive.org/web/20170831135842/http://wiki.fasterxml.com/JacksonJsonViews )
Quoting it:
First, defining views means declaring classes; you can reuse existing ones, or just create bogus classes -- they are just view identifiers with relationship information (child inherits view membership from parents):
// View definitions:
class Views {
static class Public { }
static class ExtendedPublic extends PublicView { }
static class Internal extends ExtendedPublicView { }
}
public class Bean {
// Name is public
#JsonView(Views.Public.class) String name;
// Address semi-public
#JsonView(Views.ExtendPublic.class) Address address;
// SSN only for internal usage
#JsonView(Views.Internal.class) SocialSecNumber ssn;
}
With such view definitions, serialization would be done like so:
// short-cut:
objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class);
// or fully exploded:
objectMapper.getSerializationConfig().setSerializationView(Views.Public.class);
// (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse)
objectMapper.writeValue(out, beanInstance); // will use active view set via Config
// or, starting with 1.5, more convenient (ObjectWriter is reusable too)
objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
and result would only contain 'name', not 'address' or 'ssn'.
You should probably look at the modules feature of recent Jackson versions.
One possible mechanism would be to use a BeanDeserializerModifier.
I've been looking for a useful online tutorial or example, but nothing immediately appears. It might be possible to work something up if more is known of your context. Are you managing your ObjectMappers manually, or using them in a JAX-RS setting, injected in Spring, or what?
I searched the entire web (yes I did) to find the answer. then I wrote something on my own.
I'm working with Jackson ion deserialisation. I wrote a custom reader that ignores the fields dynamically.
You can do the same thing for json deserialisation.
Lets assume an entity like this.
User {
id
name
address {
city
}
}
Create a tree structure to represent field selection.
public class IonField {
private final String name;
private final IonField parent;
private final Set<IonField> fields = new HashSet<>();
// add constructs and stuff
}
Custom Ion Reader extending from amazon ion-java https://github.com/amzn/ion-java
public class IonReaderBinaryUserXSelective extends IonReaderBinaryUserX {
private IonField _current;
private int hierarchy = 0;
public IonReaderBinaryUserXSelective(byte[] data, int offset, int length,
IonSystem system, IonField _current) {
super(system, system.getCatalog(), UnifiedInputStreamX.makeStream(data, offset, length));
this._current = _current;
}
#Override
public IonType next() {
IonType type = super.next();
if (type == null) {
return null;
}
String file_name = getFieldName();
if (file_name == null || SystemSymbols.SYMBOLS.equals(file_name)) {
return type;
}
if (type == IonType.STRUCT || type == IonType.LIST) {
IonField field = _current.getField(getFieldName());
if (field != null) {
this._current = field;
return type;
} else {
super.stepIn();
super.stepOut();
}
return next();
} else {
if (this._current.contains(file_name)) {
return type;
} else {
return next();
}
}
}
#Override
public void stepIn() {
hierarchy = (hierarchy << 1);
if (getFieldName() != null && !SystemSymbols.SYMBOLS.equals(getFieldName())) {
hierarchy = hierarchy + 1;
}
super.stepIn();
}
#Override
public void stepOut() {
if ((hierarchy & 1) == 1) {
this._current = this._current.getParent();
}
hierarchy = hierarchy >> 1;
super.stepOut();
}
Construct dynamic view. This Tree dynamically created and passed to the reader to deserialise.
Let's say we only need city inside the address.
IonField root = new IonField("user", null);
IonField address = new IonField("address", root);
IonField city = new IonField("city", address);
address.addChild(city);
root.addChild(id);
//now usual stuff.
IonFactory ionFactory = new IonFactory();
IonObjectMapper mapper = new IonObjectMapper(ionFactory);
File file = new File("file.bin"); // ion bytes
byte[] ionData = Files.readAllBytes(file.toPath());
IonSystem ionSystem = IonSystemBuilder.standard().build();
IonReader ionReader = new IonReaderBinaryUserXSelective(ionData, 0, ionData.length, ionSystem, root);
User user = mapper.readValue(ionReader, User.class);

Categories