I have a model with some properties e.g.
public class Example
{
long id;
String a, b;
int c, d;
boolean e;
}
Now I want to create a method like this
public void update(long id, Map<String, Object> properties)
{
....
}
in this properties map I want to have sth like
properties.put("a","Test");
properties.put("c", 8);
I'm not exactly sure on how to achieve this.
at the end I want to do sth like this:
Example e = new Example(....);
.....
e.update(5L,properties);
can some1 point me to the correct path? I cant figure out a searchterm that doesnt lead me to the Properties or HashMap entries.
thanks in advance
You are searching for the keyword reflection. With reflective access you would write your update method like that:
public void update(long id, Map<String, Object> properties) {
Object obj = getObjectById(id); // you have to implement that method
for (String property : properties.keySet()) {
Field field = obj.getClass().getField(property);
field.set(obj, properties.get(property));
}
}
Note, that I did not declare or handle any exceptions that come along with reflection.
A completely other issue: Why do you want to do it this way? Using reflection to update fields of an object smells like a real design issue. You really should consider another model.
Related
This is hard for me to explain as I'm not native to the English language, so I will try setting up an example.
I am trying to save some data about a player in a class called PlayerData. It has three variables with getters and setters.
public class PlayerData {
private String player;
private String username;
private UUID uuid;
public String getPlayer() {
return player;
}
public void setPlayer(String player) {
this.player = player;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
}
For each player in the game, there will be generated a PlayerData object. Normally I would store this in a Map, so I can get the data about a player from eg. the UUID. However, I could use a way to be able to use any variable in the PlayerData object as "key", so I don't require the UUID to get the PlayerData. A way to do this (and my usual approach) would be to have multiple maps, something like this.
Map<String, PlayerData> playerMap;
Map<String, PlayerData> usernameMap;
Map<UUID, PlayerData> uuidMap;
The problem is, when it scales up with multiple variables, this gets annoying, and perhaps even eats up the RAM? I'm not entirely sure, as it stores references.
It similar to SQL, where you can also get specific colums based on the content of the rows. That's what I'm looking for, but without the SQL database.
I made a table explanation below in an attempt to explain it further:
Player
Username
UUID
Peter
Peter1234
657f6c48-655f-11eb-ae93-0242ac130002
Stephen
DogLover69
657f6efa-655f-11eb-ae93-0242ac130002
Joshua
XxFlowerPotxX
657f6fea-655f-11eb-ae93-0242ac130002
Short edition
I'm looking for a way to store multiple objects of the same type, where I (unlike Maps, that only take a single object as Key) can use multiple assigned variables as keys.
I hope the explaination was clear, I have absoloutly no idea how to explain it, which is probably also why I can't solve it by googling.
Thank you for your time.
As far as I understand, it's need to store various data for a specific user (and not just to update old values)
One way is through a custom map. Since only need a key (unique), could assume that username is doing that (eg:login). MyData can be customized further with what ever wanted to store.
Each key/username will contain a distinct list where new data is added.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class TestPData {
public static void main(String[] args)
{
TestPData t = new TestPData();
MyMap m = t.new MyMap();
//key can be just user name, if unique is assured
m.putMyData("player_1", t.new MyData("p1_data1"));
m.putMyData("player_1", t.new MyData("p1_data2"));
m.putMyData("player_2", t.new MyData("p2_data3"));
m.putMyData("player_3", t.new MyData("p2_data4"));
m.putMyData("player_3", t.new MyData("p2_data5"));
m.putMyData("player_3", t.new MyData("p2_data6"));
m.forEach((k,v)->{for(MyData d: v) {System.out.println(k+":"+d);}});
}
class MyData
{
String s;
public MyData(String s)
{
this.s = s;
}
public String toString()
{
return s;
}
}
class MyMap extends HashMap<String, List<MyData>>
{
private static final long serialVersionUID = 1L;
public void putMyData(String k, MyData d)
{
if(!this.containsKey(k))
{
this.put(k, new ArrayList<MyData>());
this.get(k).add(d);
}
else
{
this.get(k).add(d);
}
}
}
}
Output
player_1:p1_data1
player_1:p1_data2
player_3:p2_data4
player_3:p2_data5
player_3:p2_data6
player_2:p2_data3
If you are dealing with few records (some thousands), you can use a list and iterative search as suggested by #gilbert-le-blanc, but if you need to manage huge amounts of records/attributes, it is better to use a database anyway. You can also use an in-memory database like Derby or H2.
https://www.h2database.com/
https://db.apache.org/derby/
With some effort you can create a custom collection with multi-indexed properties also, but it is not worth the pain.
I would use a map of maps, with the first mapping by the name of the property and the second map by its value.
In code:
Map<String, Map<String, PlayerData>> index = new HashMap<>();
To add a mapping:
PlayerData peterData = new PlayerData(
"Peter",
"Peter1234",
"657f6c48-655f-11eb-ae93-0242ac130002");
index.computeIfAbsent("player", k -> new HashMap<>())
.put("Peter", peterData);
index.computeIfAbsent("username", k -> new HashMap<>())
.put("Peter1234", peterData);
index.computeIfAbsent("uuid", k -> new HashMap<>())
.put("657f6c48-655f-11eb-ae93-0242ac130002", peterData);
This navigates to the different inner maps (one per indexed property) by means of the Map.computeIfAbsent method, which creates an empty inner map and puts it into the outer map if it doesn't exist, or returns it if already present. Then, we add the mapping to the inner map by using Map.put as usual.
To remove a mapping:
index.computeIfAbsent("username", k -> new HashMap<>()).remove("Peter1234");
This is completely dynamic, as you don't have to change the data structure when you need to map by more properties. Instead, all you have to do is add mappings as needed.
The downside of this approach is that you'd need to use strings for the keys of the inner maps, but I think this is a reasonable trade-off.
How to create a list of maps, where each key name is inferred from name of the class attribute, and value is to be put by getter method
I am having following class in java
class DTA {
private String id;
private String age;
#Override
public String toString() {
return "DTA{" +
"id='" + id + '\'' +
", age='" + age + '\'' +
'}';
}
public DTA(String id, String age) {
this.id = id;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
I am having a list of objects of type DTA
List<DTA> listA = new ArrayList<>();
listA.add(new DTA("A", "15"));
listA.add(new DTA("B", "25"));
I want to create an ordered list of maps (somewhat like scala) which has following content.
List<? extends Map<String, String>>
List(Map("id"->"A", "age"->"15"), Map("id"->"B", "age"->"25"))
Without "dynamics", the straight forward thing might look like:
List<Map<String, String>> x = listA
.stream()
.map(this::toMap)
.collect(Collectors.toList());
with a local helper, such as:
private Map<String, String> toMap(DTA dta) {
Map<String, String> rv = new HashMap<>();
rv.put("id", dta.getId());
rv.put("age", dta.getAge());
return rv;
}
In order to be fully dynamic here, you would have to use reflection to query the field names. You can find examples how to do that here.
But I strongly suggest to not do that: reflection should always be your last resort. The notion of DTA suggests that you have that object data coming from some "service" anyway. If so, why first serialize into a specific DTA class, to then "flatten" that information into some generic Map structure?!
Meaning: when that service gives you objects that are serialized as, say JSON, or XML ... then it would be much better to simply use a library like gson or jackson to directly deserialize that data into such generic "flat" Map-based objects. Jackson for example has a JsonNode class. When you deserialize into such objects, you get that mapping of field names for free! See here more example code.
The point is: identifying fields using reflection is possible. But reflection code is always tedious, and error prone. If possible, stay away from doing that yourself.
Basically, the tool used to "look into" the contents of classes in Java is called reflection. For example, if your object is a POJO (Plain Old Java Object), you can iterate over all fields in the class in the following way:
DTA obj; // some object, I assume it's initialized
Field[] fields = DTA.class.getDeclaredFields();
Map<String, Object> valuesMap = new HashMap<>();
for (field : fields) {
boolean wasAccessible = field.isAccessible(); // check if class has access control disabled
field.setAccessible(true); // disable access control (private/protected) to extract value
valuesMap.put(field.getName(), field.get(obj));
field.setAccessible(wasAccessible); // return flag to initial value
}
However, accessing values via reflection this way is notoriously hacky. Unless you have good reasons to do it yourself, try using a framework that automates tasks like that rather than writing code like this from scratch.
Also, reflection is slow. Accessing Field entities like that for every single object is suboptimal, if you ever want to really write code like this, you should cache the Field objects in a Map<String, Field> and only do the setAccessible override and the Field retrieval once for every collection of DTA objects.
My overall goal is to fill a Hashtable with employee data and be able to access/modify that data then print it out.
Given my Employee class here, can I use it like a struct in C? I'm trying to figure out how to initialize a Hashtable and fill it with this data but I'm sort of confused on how to implement it.
public class Employee {
private String empName;
private int empNum;
private String empJob;
public Employee(String empName, int empNum, String empJob)
{
this.empName = empName;
this.empNum = empNum;
this.empJob = empJob;
}
public int getEmpName()
{
return empName;
}
public String getEmpNum()
{
return empNum;
}
public String getEmpJob()
{
return empJob;
}
}
So, I tried this in main, using String as the key, so I want to use the names as the key so you can search by name. I'm also trying to manually fill it so I can test everything. Also, am I able to access say, the employee number on it's own? if so, how can I do this?
public class Main {
public static void main(String[] args)
{
Hashtable<String,Employee> EmployeeTable = new Hashtable<String,Employee>();
Employee Object = new Employee("Donald","Donald", 3, "Engineer");
}
}
Thanks in advance everyone!
You can add elements to your Hashtable using the put method. You just need to specify the key and the value.
Then you can retrieve values using the get method and specifying the key.
Example Usage:
Hashtable<String, Employee> table = new Hashtable<String, Employee>();
Employee bob = new Employee(...);
table.put("Bob", bob);
Then later you can say...
table.get("Bob");
and this will return Bob's Employee object for you.
Problems with your code:
There are a few problems with your code that you should be aware of.
1. Your Employee Constructor is wrong.
You've got a constructor for Product inside of your Employee class. This is illegal syntax and will not compile (I hope). Instead, you should use the Employee constructor.
2. Your Hashtable variable name matches the Object class.
You've named a variable Object. Object is the class that all java classes inherit from, so you really shouldn't name something this (if it even lets you at all).
The Object documentation mentions this...
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
3. Incorrect Hashtable types.
You've put the wrong types in your Hashtable declaration.
You wrote...
Hashtable<String, Employee> EmployeeTable = new Hashtable<String, Product>();
When really it should be...
Hashtable<String, Employee> employeeTable = new Hashtable<String, Employee>();
(Product changed to Employee)
(I also changed the variable to be lowercase)
Notes:
All of the documentation for Hashtable can be found here.
You may also be interested in using a HashMap instead of a Hashtable. They're almost identical but HashMap isn't threadsafe. You can see some of the differences here. If you really need a threadsafe map then I'd recommend ConcurrentHashMap, it's up to you to decide which one suits you the best though.
It's Java convention for variable names to start with lowercase letters. You don't have to follow this but it's definitely a good idea to. Syntax highlighters will no longer argue with you if you do.
What you want to achieve is rather this:
// Create my Hashtable using the diamond notation indicating to use the type arguments
// corresponding to the context which is <String, Employee> here
Map<String, Employee> EmployeeTable = new Hashtable<>();
Employee employee = new Employee("Donald", 3, "Engineer");
// put my employee into my map using empoyee's name as key
EmployeeTable.put(employee.getEmpName(), employee);
What you are looking for is Map#put(key, value)
After fixing several typo issues, your class Employee should be:
public class Employee {
...
public Employee(String empName, int empNum, String empJob)
{
...
}
public String getEmpName()
{
return empName;
}
public int getEmpNum()
{
return empNum;
}
...
}
NB: Hashtable is an outdated class, you should not use it anymore, if you don't intend to share it use an HashMap instead and if you want to share it use a ConcurrentHashMap
There are various things wrong with your class.
Example: the class is called Employee. Then the constructor must use that name, and nothing else!
So, it shouldn't read
public Product(String empName, int empNum, String empJob)
but
public Employee(String empName, int empNum, String empJob)
And then your call
Hashtable<String,Employee> EmployeeTable = new Hashtable<String,Product>();
could be correctly written down as
Hashtable<String,Employee> table = new Hashtable<>();
And no, a Hashtable is not a struct. A hashtable is a collection class; in other words: it is a Map. It maps a key (String in your case) to Employee objects.
But, well, stackoverflow is not a service where other people debug and explain your code to you. So, take my input as starting point; and for example: start reading the compiler messages.
I write a little web API which should it make easy to create URIs. Each resource class should contain a method createURI which takes the needed parameters. This method should use a helper method, populateUriTemplate, in the background to create an URI string. populateUriTemplate needs key value pairs to populate an URI template. In another language like Scala or Python I would use named parameters, but Java doesn't support them. So the question is: How to simulate named parameters in Java?
The straight forward solution would be to create a map:
public String createUri(int id, String name){
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", id);
params.put("name", name);
return populateUriTemplate(params);
}
But I don't like to create a map first and put each parameter to it.
Another idea is to use a static method, param, to create key value pairs:
public String createUri(int id, String name){
return populateUriTemplate(param("id", id), param("name", name));
}
Looks much better to me!
It could be refined a bit to make it more self-explanatory, even if a few more characters are needed:
public String createUri(int id, String name){
return populateUriTemplate(key("id").value(id), key("name").value(name));
}
I've also thought of the builder pattern, but this would force the user of my API to create an explicit builder for each resource class, what would be tedious without a benefit. The type of the parameter is not important, as long as a proper implemented toString method exists.
My favourite is one of the both approaches with the static methods above (param(key, value) or key(k).value(v)). Do you know a better way to simulate named parameters in this case?
For some ideas on the builder pattern, you could see this blog post by Stephan Schmidt.
You also just gave me the idea to do the following, with fluent interfaces, a Callable, and a static method:
createUri().id(5).name("dennetik").call();
Which would require createing a Callable class (CreateUri) with the static method:
public static final CreateUriFluentInterface createUri() {
return FluentInterface.of(new CreateUri(), CreateUriFluentInterface.class);
}
And a fluent interface, like this:
public interface CreateUriFluentInterface {
public CreateUriFluentInterface id(Integer id);
public CreateUriFluentInterface name(String name);
}
Which isn't that much boilerplate code, is it?
(Well, if you tone down that horribly named CreateUriFluentInterface a bit, it isn't.)
(You would probably have CreateUriFluentInterface extend Callable<String>, to be able to reroute the call to Callable#call())
populateUriTemplate("id",id, "name",name);
void populateUriTemplate(Object... nvs){
for(int i=0; i<nvs.length/2; i++)
....
}
Maybe you like this approach:
class Params {
private HashMap<String, Object> allParams = new HashMap<String,Object>();
public Params(ParamEntry...params) {
for( ParamEntry p : params ) {
allParams.put(p.name, p.value);
}
}
public getParam(String name) {
return allParams.get(name);
}
class ParamEntry {
public String name;
public Object value;
}
}
public String createUri(Params.ParamsEntry ... params){
return populateUriTemplate(new Params(params));
}
To call it use
createUri(new Param.ParamEntry("name", valueObject) );
Inside the populateUriTemplate...
just use params.get("name");
Spring MVC does exactly this. As well as being able to bind requests to specific methods in controller classes, you can bind request parameters to method parameters. You can have a look to see how it works, but basically it picks a strategy to map the right request parameter to the right method parameter.
You basically get something like:
public String createUri(#RequestParam int id, #RequestParam String name){
return populateUriTemplate(id, name);
}
This is almost silly and slightly off topic, but using Lombok's #Builder annotation takes this closer to the desired result.
Furthermore if the builder, builder method and build method names are changed to _ they almost disappear:
import static foo.Template._;
class Resource {
String createURI(String id, String name) {
return populateURITemplate(_.id(id).name(name)._());
}
String populateURITemplate(Template t ){
return t.id+"="+t.name;
}
}
#Builder(builderClassName = "_", builderMethodName = "_", buildMethodName = "_" )
class Template {
static _ _ = _();
String id;
String name;
}
Named parameters are not the way:
Named parameters do not make your code any cleaner in this case. I would argue that they make things more complex and error prone in Java because you lose type safety and you lose compiler warnings about identifiers that do not exist.
TypeSafe Immutable Fluent Builders:
I wrote an article on a UrlBuilder implementation earlier this year, it shows a type safe fluent interface that enforces order of construction for mandatory input and allows for optional parts with sane defaults as well.
Now I will be the first to admit that the approach I use is fairly verbose, but it is extremely productive once that initial price is paid. It works with dependency injection and is easily unit testable and most importantly is composable for specialization.
final URL url1 = new UrlBuilder().scheme("http").host("www.google.com").build();
System.out.println("url1 = " + url1);
final URL url2 = new UrlBuilder().scheme("https").userInfo("xkcd", "correcthorsebatterystaple").host("admin.xkcd.com").build();
System.out.println("url2 = " + url2);
Produces:
url1 = http://www.google.com
url2 = https://xkcd:correcthorsebatterystaple#admin.xkcd.com
I am addressing the verbosity of the anonymous inner class implementations of the interfaces with another approach I am experimenting with; type safe implementations of value objects from interfaces using dynamic proxies.
This will do away with the boilerplate value objects and replace them with Map<String,?> but put a dynamically generated type safe immutable Interface wrapper around them.
I encourage you to read about both of these and see how combining them gives you a better solution than named properties ever would.
When I get time to refactor my UrlBuilder with the dynamic proxies I will post another blog post about it as well.
Named Parameters via Guice
If you are dead set on named parameters then I would recommend looking at Guice #Named bindings. You still lose the compile type checks and safety but at least you get some validations from Guice.
public class RealBillingService implements BillingService {
#Inject
public RealBillingService(#Named("Checkout") CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
I have a Map Object and the data in map is like
col1 -> data1, col2 -> data2, col3 -> data3 ...
Is it possible to convert this Map to Java Object like
class MapObj {
String col1 = "data1";
String col2 = "data2";
String col3 = "data3";
}
Whilst it is possible to create classes at runtime with custom class loaders, it is relatively pointless. How would you access the fields (other than reflection and other dynamically created classes)?
use Jackson
import com.fasterxml.jackson.databind.ObjectMapper;
public class Foo {
{
ObjectMapper objectMapper = new ObjectMapper();
YourObject obj = objectMapper.convertValue(YourMap, YourObject.class);
}
}
BeanUtils.populate(entry,map);
Are there a fixed set of named entries in the Map? If so, you can just create the MapObj class as you have it and assign the three fields by saying myMapObj.col1 = myMap.get("col1"); and so on.
But stepping back from this question for a moment, what's the larger problem you're trying to solve? A Map itself is actually a very convenient container for this data already, so perhaps you can just use the Map for the same purpose that you were planning to use MapObj for?
I don't see any point in putting a bunch of Map values to a class.
If you want static access, why not try the opposite:
class MapAccess {
Map<String, String> backingMap = ...
public String getCol1() {
return backingMap.get("col1");
}
public String getCol2() {
return backingMap.get("col2");
}
public String getCol3() {
return backingMap.get("col3");
}
}
This way, you'r application doesn't need to know about the Map and you don't get lost with reflection.
I don't know of any pre-made libs that will do it for you, but it should be quite trivial using the java.lang.reflect API. Specifically, the Field#set* methods. Of course, however, you would need to have a pre-defined class with the fields (keys) defined.