Having Student Class.
Class Student{
String _name;
....
....
public Student(){
}
}
is there any possibility to add dynamic attributes to Student Object?
without extending the student class.
In short, yes it is possible to modify bytecode at runtime, but it can be extremely messy and it (most likely) isn't the approach you want. However, if you decide to take this approach, I recommend a byte code manipulation library such as ASM.
The better approach would be to use a Map<String, String> for "dynamic" getters and setters, and a Map<String, Callable<Object>> for anything that isn't a getter or setter. Yet, the best approach may be to reconsider why you need dynamic classes altogether.
public class Student {
private Map<String, String> properties = new HashMap<String, String>();
private Map<String, Callable<Object>> callables = new HashMap<String, Callable<Object>>();
....
....
public String getProperty(String key) {
return properties.get(key);
}
public void setProperty(String key, String value) {
properties.put(key, value);
}
public Object call(String key) {
Callable<Object> callable = callables.get(key);
if (callable != null) {
return callable.call();
}
return null;
}
public void define(String key, Callable<Object> callable) {
callables.put(key, callable);
}
}
As a note, you can define void methods with this concept by using Callable and returning null in it.
You could get into bytecode manipulation but that way madness lies (especially for the programmer who has to maintain the code).
Store attributes in a Map<String,String> instead.
Although you can do that with some tricky, and complex way that others have suggested..
But you can sure have your attributes in some data structure(An appropriate one will be a Map).. Since you can modify your existing attributes, so can be done with you Data Structure. You can add more attributes to them.. This will be a better approach..
Related
I want to define a DAO over a DynamoDB that has 20+ fields. In Java, I can use Lombok and do something like this to avoid a bunch of boilerplate code.
#Setter
#Getter
#DynamoDBTable("MyTable")
public class MyDAO {
//FIELD_1, FIELD_2, FIELD_3 defined as static final String elsewhere
#DynamoDBAttribute(attribute = FIELD_1)
private final String field1;
#DynamoDBAttribute(attribute = FIELD_2)
private final Long field2;
#DynamoDBAttribute(attribute = FIELD_3)
private final int field3;
...
}
The problem is if I had methods that did something for each field like the following, I would end up duplicating the code over and over again, because the setters in step 2 would be different and the field names in step 3 would be different (i.e. setField1 for the first and setField2 for the second).
public void addField1(String key, String field1Value) {
//Wrap some retry logic and error handling around the following
// 1. get DAO for key
// 2. set FIELD_1 to field1Value in DAO if not set
// 3. put DAO in DynamoDB using attribute name FIELD_1
}
public void addField2(String key, Long field2Value) {
//Wrap some retry logic and error handling around the following
// 1. get DAO for key
// 2. set FIELD_2 to field2Value in DAO if not set
// 3. put DAO in DynamoDB using attribute name FIELD_2
}
Ideally, I would like to have something like the addField method below, with all the retry logic so I don't have to duplicate everything for every field.
private void addField(String fieldName, String key, Object value);
public void addField1(String key, String field1Value) {
addField(FIELD_1, key, (Object) field1Value);
}
I've tried a map between field names and BiConsumers as such
Map<String, BiConsumer<MyDAO, Object>> setterMap =
new HashMap<String, BiConsumer<MyDAO, Object>>(){{
put(FIELD_1, MyDAO::setField1);
put(FIELD_2, MyDAO::setField2);
}};
private void addField(String fieldName, String key, Object value) {
...
// 2. Use setterMap.get(fieldName).accept(value);
...
}
The problem is I get an error saying that I cannot cast BiConsumer<MyDAO, String> to BiConsumer<MyDAO, Object>.
Is it the only way to do it - to create a separate map and method for each type? Or is there a more elegant way to do this?
Well, I don't think it's possible to do it using a Map if you want to preserve type safety. Instead, here's what I would do:
1) I'd create a special class like that:
#AllArgsConstructor
#Getter
final class FieldDefinition<T> {
private final String name;
private final BiConsumer<MyDAO, T> setter;
}
2) Then, I'd create constants in MyDAO (or, even better, in some helper object near MyDAO) like that:
static final FieldDefinition<String> FIELD_1_DEF = new FieldDefinition<>(FIELD_1, MyDAO::setField1);
3) Finally, I'd create the following type-safe addField method:
private <T> void addField(FieldDefinition<T> fieldDefinition, String key, T value) {
// ...
fieldDefinition.getSetter().accept(this, value);
// ...
}
which whould be called like that:
myDao.addField(FIELD_1_DEF, key, value);
Dynamic selection of methods is really not a good fit for functional interfaces. Parameterizing your code around method selection is better done with reflection, rather than with functional interfaces.
The main reason making it difficult to implement your logic using the BiConsumer interface is that you would technically still have to provide static implementations for it, for each field (whether using lambdas, method references, or classes...).
Here's an example reflection-based implementation:
private void addField(String fieldName, String key, Object value) {
MyDAO.class.getDeclaredField(fieldName).set(value, key);
}
So I'd just make setterMap a map of key to field name mapping, and use it like so:
private void addField(String key, Object value) {
String field = setterMap.get(key);
MyDAO.class.getDeclaredField(field).set(value, key);
}
I need to get a Field (or a list of Fields) without knowing it's name.
I.e: for a custom entitymanager i'd like to be able to do Method Calls like this:
cem.getEntities(MyEntity.class, ParamMap) where the ParamMap should be of the Type Map<Field, Object>.
What i can do at the moment is something like this:
Map<Field, Object> params = new HashMap<Field, Object>();
params.put(MyEntity.class.getDeclaredField("someFieldName"), 20);
List<MyEntity> entitysWithSomeFieldNameEquals20 = cem.getEntities(MyEntity.class, params);
Im trying to avoid the usage of querys, because it should work "generic" in the first place, but also be independent from Strings. (They are error-prone). The Entity Manager therefore uses reflection to determine the table and column names, he needs to use.
However, I STILL need to use
MyEntity.class.getDeclaredField("someFieldName")
which will simple move the error-prone string "out" of the entity manager...
What i'm trying to achieve would be something like this:
MyEntity.class.getDeclaredField(MyEntity.class.fields.someFieldName.toString())
So, no matter what the actual field is named, it can be referenced in a save way and refactoring will refactor all the field-access calls, too.
I'm not sure if this is possible. I could go with a (encapsuled) enum for ALL entities, but I hope, that theres a more generic way to achieve this.
Edit:
One good solution seems to be the usage of constants:
public class MyEntity{
private static string SOME_FIELD = "some_field_name_in_database";
#Column(name = SOME_FIELD);
private String someField;
}
...
Map<String, Object> params = new HashMap<String, Object>();
params.put(MyEntity.SOME_FIELD, matchValue);
List<MyEntity> result = eem.getEntities(MyEntity.class, params);
This at least reduces the usage of the string to exactly one location, where it can be maintained and changed without affecting any other file. But im still searching for a solution without constants, so the contants don't need to be synchronized with the available fields :-)
Ok, this is just an idea, which is not easy to implement, but it could work.
Suppose MyEntity looks like this:
public class MyEntity {
private String foo;
private String bar;
public String getFoo() { return this.foo; }
public void setFoo(String foo) { this.foo = foo; }
public String getBar() { return this.bar; }
public void setBar(String bar) { this.bar = bar; }
}
and there is an interface:
public interface Pattern {
public Class<?> getEntityClass();
public Map<Field, Object> getFields();
}
and there is a method, which takes a class and generates a pattern object, which is an instance of the given class:
public class PatternFactory {
public <T> T createPattern(Class<T> klass) {
// magic happens here
}
}
The requirement for the emitted instance would be that it should implement the Pattern interface, such that the method getFields returns only the fields which were explicitly set. GetEntityClass should return the entity class. Then the custom entity manager could be implemented like this:
public class EntityManager {
public <T> Collection<T> getEntities(T pattern) {
if (!(pattern instanceof Pattern))
throw new IllegalArgumentException();
Class<?> klass = ((Pattern) pattern).getEntityClass();
Map<Field, Object> fields = ((Pattern) pattern).getFields();
// fetch objects here
}
}
Then you could use it like this:
PatternFactory pf = // obtain somehow
EntityManager em = // obtain somehow
MyEntity pattern = pf.createPattern(MyEntity.class);
pattern.setFoo("XYZ");
pattern.setBar(null);
Collection<MyEntity> result = em.getEntities(pattern);
In this case pattern.getFields would return a map with two entries.
The difficulty here lies, of course, in the implementation of the createPattern method, where you will have to emit bytecode at run-time. However, this is possible and can be done.
I've made some custom beans that implement the Map interface for easy access to arbitrary data in my JSP.
Example:
${person["cellPhoneNumber"]}
This extra data may or may not be added on the back end so a Map seems like a nice flexible way to store this.
The problem arises when I try to use the getters on my bean. My Person class has a getName() method. When using the following in my JSP, the Map.get() method is called instead of my method.
${person.name}
Is there a way to get around this call to Map's get("name") and call getName() instead?
Here is my basic (stripped down) Java class:
class Person implements Map
{
private HashMap<String, Object> myMap;
private String name;
public Object get(Object key)
{
return myMap.get(key);
}
public String getName()
{
return this.name;
}
}
Using JSTL 1.1
Looks like servlet container treats every class implementing Map interface as a map and completely discards other methods, falling back to by key lookup. I see two solutions:
1) get(Object key) should be aware of normal properties:
class Person implements Map
{
private HashMap<String, Object> myMap;
private String name;
public Object get(Object key)
{
switch(key) {
case "name": return getName();
default: myMap.get(key)
}
}
public String getName()
{
return this.name;
}
}
This is a bit clumsy and not very scalable. Also it's probably easier to either use reflection and find all fields automatically or convert your bean to map (see: How to convert a Java object (bean) to key-value pairs (and vice versa)?). Even worse.
2) Expose your map as a special bean attribute:
class Person
{
private HashMap<String, Object> optional;
private String name;
public Map<String, Object> getOptional()
{
return optional;
}
public String getName()
{
return this.name;
}
}
Then your EL expression looks like this:
${person.optional['cellPhoneNumber']}
This is a much better approach since:
it's faster and more scalable
better represents your intent
it's a better design (as highlighted by duffymo in comments) - Person has optional attributes like cell phone number. Person is not a ``Map` of optional attributes.
I am wondering whether I am overusing java reflection.
I have a class which is a data holder for a couple of maps. I have public get(...) methods which given a key as input return the value associated with it in the corresponding map.
Since the maps are large I load them only when I actually want to access them. So, in every get(...) methods, I check whether the map is null. If it is, I call the corresponding loadMap(..) method.
Here is a sample code snippet
public getId(String name)
{
try
{
if(nameMap1 == null)
loadNameMap1();
} catch(...) {....}
return nameMap1.getId(name);
}
The problem is that I have multiple maps. So, for loading each map I have a different loadMap(..) method and the try catch block in the get(...) methods. So, instead of that I wrote a method called loadMap(Object map, String methodName) which uses reflection to call the appropriate method, and handles all exceptions.
private synchronized void loadMap(Object map, String methodName)
{
if (map == null)
try
{
Method method = this.getClass().getDeclaredMethod(methodName, new Class[0]);
method.invoke(this, new Object[0]);
}
catch (..)
}
Am I overusing reflection here? Is there a better way to do this? Does this qualify as "limited use of reflection" as written in Effective Java by Joshua Bloch
(Side note: I cannot refactor the class into multiple classes )
// could also be static
private Map<String, Callable<Map>> myLoaders;
private synchronized void loadMap(Object map, String mapName)
{
if (map == null)
try
{
Callable<Map> mapLoader = myLoaders.get(mapName);
map = mapLoader.call();
}
catch (..)
}
// and in the constructor or other init code
myLoaders.put("map1", new Callable<Map>(){
Map call(){
// load map 1
}});
I think, though that if all you are doing is move a common try/catch logic from a couple of methods were it needs to be repeated to a single place, this is the wrong approach. You lose a lot of compiler error checking support this way. Some people would use a tool like Aspect/J for this, but I think you just have to live with the fact that Java has no real facility for this, reduce the clutter to a minimum by using shared private functions, and accept the couple of copy/pasted lines. As long as there is no "real code" in those lines, it is not really harmful code duplication.
So:
public getId(String name){
try{
if (nameMap1 == null)
loadNameMap1();
}
catch (....){
privateHelperFunctionThatCutsThisDownToOneLine(name, "id", "nameMap1");
}
}
// you are left with the above repetitive three (or seven) lines,
// but that is Java for you...
// in return, you get nice, static compile-time error checking
private void privateHelperFunctionThatCutsThisDownToOneLine(){
// all the long repeated code in the exception handler
// goes here.
}
You don't want to load all the maps because they are too large. But using your method you're gonna end up with everything loaded in memory eventually. You may have a look at ehcache which may be configured a a lazy map system with element eviction when no longer needed.
I'd say yes you are overusing reflection.
Perhaps you should take a more OO approach
public interface MapMaker <K,V> {
public Map<K,V> create();
}
public class LazyMap<K,V> implements Map<K,V> {
private MapMaker<K,V> creation;
private Map<K,V> theMap = null;
public LazyMap( MapMaker<K,V> creation) {
this.creation=creation;
}
protected Map<K,V> getMap() {
if( theMap == null) {
synchronized(this) {
if( theMap == null ) {
theMap = creation.create();
}
}
}
return theMap;
}
//Map interface
public V get(Object key) { return getMap().get(key); }
//repeat for all
}
I'd like to add a method AddDefaultNamespace() to the String class in Java so that I can type "myString".AddDefaultNamespace() instead of DEFAULTNAMESPACE + "myString", to obtain something like "MyDefaultNameSpace.myString". I don't want to add another derived class either (PrefixedString for example).
Maybe the approach is not good for you but I personally hate using +. But, anyway, is it possible to add new methods to the String class in Java?
Thanks and regards.
String is a final class which means it cannot be extended to work on your own implementation.
Well, actually everyone is being unimaginative. I needed to write my own version of startsWith method because I needed one that was case insensitive.
class MyString{
public String str;
public MyString(String str){
this.str = str;
}
// Your methods.
}
Then it's quite simple, you make your String as such:
MyString StringOne = new MyString("Stringy stuff");
and when you need to call a method in the String library, simple do so like this:
StringOne.str.equals("");
or something similar, and there you have it...extending of the String class.
As everyone else has noted, you are not allowed to extend String (due to final). However, if you are feeling really wild, you can modify String itself, place it in a jar, and prepend the bootclasspath with -Xbootclasspath/p:myString.jar to actually replace the built-in String class.
For reasons I won't go into, I've actually done this before. You might be interested to know that even though you can replace the class, the intrinsic importance of String in every facet of Java means that it is use throughout the startup of the JVM and some changes will simply break the JVM. Adding new methods or constructors seems to be no problem. Adding new fields is very dicey - in particular adding Objects or arrays seems to break things although adding primitive fields seems to work.
It is not possible, since String is a final class in Java.
You could use a helper method all the time you want to prefix something. If you don't like that you could look into Groovy or Scala, JRuby or JPython both are languages for the JVM compatible with Java and which allow such extensions.
YES!
Based on your requirements (add a different namespace to a String and not use a derived class) you could use project Lombok to do just that and use functionality on a String like so:
String i = "This is my String";
i.numberOfCapitalCharacters(); // = 2
Using Gradle and IntelliJ idea follow the steps below:
Download the lombok plugin from intelliJ plugins repository.
add lombok to dependencies in gradle like so: compileOnly 'org.projectlombok:lombok:1.16.20'
go to "Settings > Build > Compiler > Annotation Processors" and enable annotation processing
create a class with your extension functions and add a static method like this:
public class Extension {
public static String appendSize(String i){
return i + " " + i.length();
}
}
annotate the class where you want to use your method like this:
import lombok.experimental.ExtensionMethod;
#ExtensionMethod({Extension.class})
public class Main {
public static void main(String[] args) {
String i = "This is a String!";
System.out.println(i.appendSize());
}
}
Now you can use the method .appendSize() on any string in any class as long as you have annotated it and the produced result for the above example
This is a String!
would be:
This is a String! 17
The class declaration says it all pretty much,as you cannot inherit it becouse it's final.
You can ofcourse implement your own string-class, but that is probaby just a hassle.
public final class String
C# (.net 3.5) have the functionality to use extender metods but sadly java does not. There is some java extension called nice http://nice.sourceforge.net/ though that seems to add the same functionality to java.
Here is how you would write your example in the Nice language (an extension of
Java):
private String someMethod(String s)
{
return s.substring(0,1);
}
void main(String[] args)
{
String s1 = "hello";
String s2 = s1.someMethod();
System.out.println(s2);
}
You can find more about Nice at http://nice.sf.net
Not possible, and that's a good thing. A String is a String. It's behaviour is defined, deviating from it would be evil. Also, it's marked final, meaning you couldn't subclass it even if you wanted to.
As everybody else has said, no you can't subclass String because it's final. But might something like the following help?
public final class NamespaceUtil {
// private constructor cos this class only has a static method.
private NamespaceUtil() {}
public static String getDefaultNamespacedString(
final String afterDotString) {
return DEFAULT_NAMESPACE + "." + afterDotString;
}
}
or maybe:
public final class NamespacedStringFactory {
private final String namespace;
public NamespacedStringFactory(final String namespace) {
this.namespace = namespace;
}
public String getNamespacedString(final String afterDotString) {
return namespace + "." + afterDotString;
}
}
People searching with keywords "add method to built in class" might end up here. If you're looking to add method to a non final class such as HashMap, you can do something like this.
public class ObjectMap extends HashMap<String, Object> {
public Map<String, Object> map;
public ObjectMap(Map<String, Object> map){
this.map = map;
}
public int getInt(String K) {
return Integer.valueOf(map.get(K).toString());
}
public String getString(String K) {
return String.valueOf(map.get(K));
}
public boolean getBoolean(String K) {
return Boolean.valueOf(map.get(K).toString());
}
#SuppressWarnings("unchecked")
public List<String> getListOfStrings(String K) {
return (List<String>) map.get(K);
}
#SuppressWarnings("unchecked")
public List<Integer> getListOfIntegers(String K) {
return (List<Integer>) map.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, String>> getListOfMapString(String K) {
return (List<Map<String, String>>) map.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, Object>> getListOfMapObject(String K) {
return (List<Map<String, Object>>) map.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, Object> getMapOfObjects(String K) {
return (Map<String, Object>) map.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, String> getMapOfStrings(String K) {
return (Map<String, String>) map.get(K);
}
}
Now define a new Instance of this class as:
ObjectMap objectMap = new ObjectMap(new HashMap<String, Object>();
Now you can access all the method of the built-in Map class, and also the newly implemented methods.
objectMap.getInt("KEY");
EDIT:
In the above code, for accessing the built-in methods of map class, you'd have to use
objectMap.map.get("KEY");
Here's an even better solution:
public class ObjectMap extends HashMap<String, Object> {
public ObjectMap() {
}
public ObjectMap(Map<String, Object> map){
this.putAll(map);
}
public int getInt(String K) {
return Integer.valueOf(this.get(K).toString());
}
public String getString(String K) {
return String.valueOf(this.get(K));
}
public boolean getBoolean(String K) {
return Boolean.valueOf(this.get(K).toString());
}
#SuppressWarnings("unchecked")
public List<String> getListOfStrings(String K) {
return (List<String>) this.get(K);
}
#SuppressWarnings("unchecked")
public List<Integer> getListOfIntegers(String K) {
return (List<Integer>) this.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, String>> getListOfMapString(String K) {
return (List<Map<String, String>>) this.get(K);
}
#SuppressWarnings("unchecked")
public List<Map<String, Object>> getListOfMapObject(String K) {
return (List<Map<String, Object>>) this.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, Object> getMapOfObjects(String K) {
return (Map<String, Object>) this.get(K);
}
#SuppressWarnings("unchecked")
public Map<String, String> getMapOfStrings(String K) {
return (Map<String, String>) this.get(K);
}
#SuppressWarnings("unchecked")
public boolean getBooleanForInt(String K) {
return Integer.valueOf(this.get(K).toString()) == 1 ? true : false;
}
}
Now you don't have to call
objectMap.map.get("KEY");
simply call
objectMap.get("KEY");
Better use StringBuilder, which has method append() and does the job you want. The String class is final and can not be extended.
No You Cannot Modify String Class in java. Because It's final class. and every method present in final class by default will be final.
The absolutely most important reason that String is immutable or final is that it is used by the class loading mechanism, and thus have profound and fundamental security aspects.
Had String been mutable or not final, a request to load "java.io.Writer" could have been changed to load "mil.vogoon.DiskErasingWriter"
All is said by the other contributors before. You can not extend String directly because it is final.
If you would use Scala, you can use implicit conversions like this:
object Snippet {
class MyString(s:String) {
def addDefaultNamespace = println("AddDefaultNamespace called")
}
implicit def wrapIt(s:String) = new MyString(s)
/** test driver */
def main(args:Array[String]):Unit = {
"any java.io.String".addDefaultNamespace // !!! THAT is IT! OR?
}
The Java String class is a final, making it immutable. This is for efficiency reasons and that it would be extremely difficult to logically extend without error; the implementers have therefore chosen to make it a final class meaning it cannot be extended with inheritance.
The functionality you wish your class to support is not properly part of the regular responsibilities of a String as per the single responsibility principle, a namespace it is a different abstraction, it is more specialised. You should therefore define a new class, which includes String a member and supports the methods you need to provide the namespace management you require.
Do not be afraid to add abstractions (classes) these are the essence of good OO design.
Try using a class responsibility collaboration (CRC) card to clarify the abstraction you need.
You can do this easily with Kotlin. You can run both the kotlin code from within the java and the java code from the kotlin.
Difficult jobs that you can do with Java can be done more easily with Kotlin. I recommend every java developer to learn kotlin.
Referance: https://kotlinlang.org/docs/java-to-kotlin-interop.html
Example:
Kotlin StringUtil.kt File
#file:JvmName("StringUtil")
package com.example
fun main() {
val x: String = "xxx"
println(x.customMethod())
}
fun String.customMethod(): String = this + " ZZZZ"
Java Code:
package com.example;
public class AppStringCustomMethod {
public static void main(String[] args) {
String kotlinResponse = StringUtil.customMethod("ffff");
System.out.println(kotlinResponse);
}
}
output:
ffff ZZZZ
You can create your own version of String class and add a method :-)
Actually , you can modify the String class . If you edit the String.java file located in src.zip , and then rebuild the rt.jar , the String class will have more methods added by you . The downside is that that code will only work on your computer , or if you provide your String.class , and place it in the classpath before the default one .