I use a library which I need to patch. I need to fork it because Factory design patter is not used.
Library has that structure: class X that hold references to other classes, that hold references to other classes and few more layers. Class hierarchy is “tree-like” structure.
I look for best way for refactoring – flexible enough to prevent people forking it. I cannot find any best practices on that problem.
Over years I use to solve it by “Injecting Factory” – Factory pattern where parent object is being injected (DI) in factory method. I cannot find any documentation on such approach and I need some feedback on it (e.g. theory or possible problems).
Tips for preparing for a Java developer interview:
Review Java fundamentals: It is important to have a good understanding of the core concepts of Java such as Object-Oriented Programming, Data Structures, Algorithms, Exception Handling, and Multithreading.
Know the basics of frameworks and libraries: Familiarize yourself with popular Java frameworks and libraries like Spring, Hibernate, Maven, and JUnit.
Understand the interview format: Find out what type of interview you will be having. Will it be a technical interview or a behavioral interview? Knowing the interview format in advance can help you prepare better.
Research the company: Get to know the company you are interviewing with. Look at their website, read up on their products, and try to get a sense of their company culture.
Prepare questions to ask: Have some questions prepared to ask your interviewer about the company, the role, and the team you would be working with.
Be confident: Remember to be confident in your abilities and focus on showcasing your strengths during the interview.
Practice coding: Brush up on your coding skills by practicing coding problems on platforms like LeetCode or HackerRank. This will help you develop your problem-solving skills and also give you an opportunity to practice coding under pressure.
If you want to check real questions from Java Interviews, check the link. There is a lot of practical information. Research over pages inside that site could save you a lot of research.
public class SuperClass {
// some methods
}
public class SubClass extends SuperClass{
// some methods
}
So we are allowed to do this conversion:
SuperClass x = new SupClass();
Limitation
But, we are not allowed to make such conversion:
List <SubClass> listSubs = ...
List <SuperClass> listSupers = listSubs; // compile time error happens
Such a stupid language limitation!
In this case, there is no clean solution. The bad solutions produce new List and reinserts all elements into it.
Solution
But we could use "? extends Generics" structure in this way:
List <SubClass> listSubs = ...
List <? extends SuperClass> listSupers = listSubs; // NO errors
Note: It is normal that ? extends Class structure allows only supclasses of the generics to be used. I was glad to understand that you could use the generics type itself there. So it is also possible:
List <? extends SuperClass> listSupers = new LinkedList(); // NO errors
Error: "class or interface without bounds" solved
Example:
public List<? extends SuperClass> getObjects() { List<? extends SuperClass> result = new ArrayList<? extends SuperClass>(1); // error: "class or interface without bounds" result.add( theNeededObject ); // error: "not suitable method found for ..." return result; }
Fixed error:
public List<? extends SuperClass> getObjects() { List<SuperClass> result = new ArrayList<>(1); result.add( theNeededObject ); return result; // it is automatically converted from <SuperClass> to "<? extends SuperClass>" }
@NamedQueries({
@NamedQuery(name = "MyClass.getBySomething",
query = " select mc from MyClass mc " +
" where mc.something = :something"),
@NamedQuery(name = "MyClass.getBySomethingOther",
query = " select mc from MyClass mc " +
" where mc.somethingOther = :somethingOther")
})
public class MyClass {
// ...
}
After you have added a new dependency, you could have exception like this:
NetBeans error:
--- exec-maven-plugin:1.2.1:exec (default-cli) @ integration --- java.lang.NoClassDefFoundError: path/to/the/class/ClassName at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) at java.lang.Class.privateGetMethodRecursive(Class.java:3048) at java.lang.Class.getMethod0(Class.java:3018) at java.lang.Class.getMethod(Class.java:1784) at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526) Caused by: java.lang.ClassNotFoundException: package.ClassName at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 7 more
JPA experience desynchronization between read data and cache while executing modifying queries. Even in the same application. It is helpful to know JPA behavior to avoid cache issues.
In short
Update queries: Lets have an update statement, which will update all rows in the database (no where cause). It will be executed on the database itself only - updating first level cache and second level cache will not be executed. Next time you access some row via that cache, you will get the old value (if the cache has not been invalidated because of timeout).
Delete queries: deleting all rows with JPQL will result removing them from database but they will stay in both caches.
1st Level Cache
If you bypass JPA and execute DML directly on the database, either through native SQL queries, JDBC, or JPQL UPDATE or DELETE
queries, then the database can be out of synch with the 1st level
cache. If you had accessed objects before executing the DML, they will
have the old state and not include the changes. Depending on what you
are doing this may be ok, otherwise you may want to refresh the affected
objects from the database.
The 1st level, or EntityManager cache can also span transaction boundaries in JPA. A JTA managed EntityManager
will only exist for the duration of the JTA transaction in JEE.
Typically the JEE server will inject the application with a proxy to an EntityManager, and after each JTA transaction a new EntityManager will be created automatically or the EntityManager will be cleared, clearing the 1st level cache. In an application managed EntityManager, the 1st level cache will exist for the duration of the EntityManager. This can lead to stale data, or even memory leaks and poor performance if the EntityManager is held too long. This is why it is generally a good idea to create a new EntityManager per request, or per transaction. The 1st level cache can also be cleared using the EntityManager.clear() method, or an object can be refreshed using the EntityManager.refresh() method.
2nd Level Cache
If the application is the only application and server accessing the database there is little issue with the 2nd level cache, as it should always be up to date. The only issue is with DML, if the application executes DML directly to the database through native SQL queries, JDBC, or JPQL UPDATE or DELETE queries. JPQL queries should automatically invalidate the 2nd level cache, but this may depend on the JPA provider. If you use native DML queries or JDBC directly, you may need to invalidate, refresh or clear the objects affected by the DML.
If there are other applications, or other application servers accessing the same database, then stale data can become a bigger issue. Read-only objects, and inserting new objects should not be an issue. New objects should get picked up by other servers even when using caching as queries typically still access the database. It is normally only find() operations and relationships that hit the cache. Updated and deleted objects by other applications or servers can cause the 2nd level cache to become stale.
For deleted objects, the only issue is with find() operations, as queries that access the database will not return the deleted objects. A find() by the object's Id could return the object if it is cached, even if it does not exist. This could lead to constraint issues if you add relations to this object from other objects, or failed updates, if you try to update the object. Note that these can both occur without caching, even with a single application and server accessing the database. During a transaction, another user of the application could always delete the object being used by another transaction, and the second transaction will fail in the same way. The difference is the potential for this concurrency issue to occur increases.
For updated objects, any query for the objects can return stale data. This can trigger optimistic lock exceptions on updates, or cause one user to overwrite another user's changes if not using locking. Again note that these can both occur without caching, even with a single application and server accessing the database. This is why it is normally always important to use optimistic locking. Stale data could also be returned to the user.
Refreshing
Refreshing is the most common solution to stale data. Most application users are familiar with the concept of a cache, and know when they need fresh data and are willing to click a refresh button. This is very common in an Internet browser, most browsers have a cache of web pages that have been accessed, and will avoid loading the same page twice, unless the user clicks the refresh button. This same concept can be used in building JPA applications. JPA provides several refreshing options, see refreshing.
Some JPA providers also support refreshing options in their 2nd level cache. One option is to always refresh on any query to the database. This means that find() operations will still access the cache, but if the query accesses the database and brings back data, the 2nd level cache will be refreshed with the data. This avoids queries returning stale data, but means there will be less benefit from caching. The cost is not just in refreshing the objects, but in refreshing their relationships. Some JPA providers support this option in combination with optimistic locking. If the version value in the row from the database is newer than the version value from the object in the cache, then the object is refreshed as it is stale, otherwise the cache value is returned. This option provides optimal caching, and avoids stale data on queries. However objects returned through find() or through relationships can still be stale. Some JPA providers also allow find() operation to be configured to first check the database, but this general defeats the purpose of caching, so you are better off not using a 2nd level cache at all. If you want to use a 2nd level cache, then you must have some level of tolerance to stale data.
Here are results of comparison of getting single result of Files.newDirectoryStream() and File.exists().
Wildcards pattern I used is "prefix_prefix_prefix____?.tmp". Results are almost the same when calling Files.newDirectoryStream() with string argument with no wildcard (direct match).
Test results 1:
measure exists speed in loop 1000 times - BEGIN measure exists speed in loop 1000 times - END Elapsed: 5 ms
Test results 2:
measure wildcards match speed in loop 1000 times - BEGIN measure wildcards match speed in loop 1000 times - END Elapsed: 80590 ms
Test environment:
Windows 7 system
NTFS system
Folder with 90 000 files (zero length)
Java 8
dir approach
I looped this MSDOS command for 1000 times to check performance of dir with wildcards:
dir prefix_prefix_prefix____*.tmp
I tested it in loop with: FOR /L %i IN (1,1,1000) DO @dir prefix_prefix_prefix____*.tmp > nul
It finished in about 1000ms. I suppose this time is spend mainly in calling DIR command by command interpreter.
Conclusion
Files.newDirectoryStream() has absolutely no performance optimizations when working with wildcards.
public static DirectoryStream<Path> newDirectoryStream(Path dir, String glob)
throws IOException
{
// avoid creating a matcher if all entries are required.
if (glob.equals("*"))
return newDirectoryStream(dir);
// create a matcher and return a filter that uses it.
FileSystem fs = dir.getFileSystem();
final PathMatcher matcher = fs.getPathMatcher("glob:" + glob);
DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
@Override
public boolean accept(Path entry) {
return matcher.matches(entry.getFileName());
}
};
return fs.provider().newDirectoryStream(dir, filter);
}
Good to know - Java 7 supports String type in switch statement.
Note 1: String are compared via equals() method - note, not via equalsIgnoreCase! and not via ==. Note 2: switch argument must not be null - else NullPointerException is thrown.
A short comparison of orphanRemoval and CascadeType.REMOVE properties.
CascadeType.REMOVE
CascadeType.REMOVE (and also CascadeType.ALL as a private case) tells the DB to delete all child records when the parent is deleted. That is if I delete the INVOICE, then delete all of the ITEMS on that INVOICE.
orphanRemoval=true
orphanRemoval=true tells the ORM that if I remove an Item object from the collection of Items that belong to an Invoice object (in memory operation), and then "save" the Invoice, the removed Item should be deleted from the underlying DB. In private case, the "collection" could be @OneToOne relationship, not just @OneToMany.
Source: some (not top rated ones!) of the comments in this stackoverflow thread.
Delete query by parent. Annotation approach used and this code is placed in repository class (interface):
@Modifying @Query("DELETE FROM Child WHERE parent = :parent")
public void deleteAllForParent( @Param("parent") Parent parent );